Documentation

Lock

Relayers management can be tricky because of nonce management. The locking mechanisms available ensure conflict-free efficient access to the shared relayers without any invalid nonce issues.

Sharing mode

Depending on your infrastructure you may need to sync the relayers access & locking between different paymaster instances. The paymaster currently support 2 sharing mode:

Segregated

  • If you have a single paymaster instance

The segregated lock system is an in-memory, single instance locking mechanism that uses standard Mutex protection with cooldown timers (to avoid invalid nonce). Whenever a thread needs a relayer to execute a transaction

  • it acquires exclusive access to the list of relayers
  • finds available relayers (enabled and not within cooldown period)
  • chooses a random relayer from the list of available relayers
  • creates a cooldown period (which is currently 5 seconds) starting from that instant ensuring that other threads dont use this relayer within this time

For unlocking a relayer after executing a transaction, the cooldown period is updated to the current instant and the nonce is updated for use in a subsequent transaction.

Shared

  • If you have multiple paymaster instances accessing the same set of relayers
  • Require a Redis configuration

The Redis locking system ensures that multiple paymaster instances can coordinate access to a set of shared relayer accounts without conflicts. It uses Redis as a distributed lock manager.

Internally, the paymaster uses keys of the form relayer-lock:{relayer_address_in_hex} to indicate a relayer is in use.

When the paymaster needs a relayer from amongst the shared relayers,

  • it gets a connection to the configured redis instance
  • gets the list of relayers
  • gets the list of locked relayers
  • finds the available relayers as the diff between list of relayers and locked relayers
  • shuffles this list to avoid collisions when selecting relayers concurrently
  • locks a relayer from this shuffled available list
  • it then creates a lock for this relayer with the cached nonce if available

For unlocking a relayer after executing the transaction, the lock key mentioned earlier is deleted after updating the cached nonce for use in a subsequent transaction.

📘

Scaling?

You can learn more about scaling, and specifically horizontal scaling here

Relayers lock properties

Prop Type Description
relayers.lock.mode "shared" | "seggregated" How to manage relayers lock
relayers.lock.redis.endpoint string(url) Redis endpoint. Only required if mode is "shared"
relayers.lock.retry_timeout number Retry to acquire a relayer until the timeout in seconds is reached

Example for Segregated Mode

{
  "relayers": {
		// ... other relayer properties
    "lock": {
      "retry_timeout": 1,
      "mode": "seggregated"
    },
   // ... other relayer properties
  },
}

Example for Shared Mode

{
  "relayers": {
		// ... other relayer properties
    	"lock": {
            "mode": "shared",
            "redis": {
                "endpoint": "redis://127.0.0.1:6379"
            }
        },
   // ... other relayer properties
  },
}