Skip to content

Latest commit

 

History

History
45 lines (40 loc) · 3.48 KB

signed-state-use.md

File metadata and controls

45 lines (40 loc) · 3.48 KB

Signed State Use

When using a SignedState, it is critically important to do so in a way that is thread safe and that does not cause improper use of the state's reference count.

FAILURE TO USE STATE RESERVATIONS CORRECTLY IS ALMOST ALWAYS FATAL TO A NODE!

While a state copy has a positive reference count, the state will not be deleted. Once all references on a state have been released, the state becomes eligible for asynchronous deletion, and will eventually be destroyed. Once all reservations on a state copy have been released, it is no longer thread safe to read, write, or otherwise do anything at all with that state copy.

Rules

  1. If an object of type SignedState is passed into a method, it is never thread safe to take a reference to the state and use it after the method is returned. a. A SignedState passed directly into a method is only guaranteed to be valid until the method returns. b. If a SignedState is passed into a method, and there is need for the signed state to be used after the method returns, then a new reservation on the signed state must be taken via ReservedSignedState ss = SignedState.reserve("reason"). c. Avoid using the merkle reference count API to force a state to remain in memory. Merkle reference counts should only be directly modified by the suite of utilities that were designed to operate directly on merkle trees.
  2. If an object of type ReservedSignedState is passed into a method, it is the responsibility of the method to guarantee that ReservedSignedState.close() is eventually called. a. If possible, use a ReservedSignedState in a try-with-resources block. b. Avoid using @Nullable ReservedSignedState parameters. As a pattern, it is better to pass a non-null ReservedSignedState wrapped around null. c. In general, prefer passing a SignedState into a method instead of a ReservedSignedState. If an implementation is synchronous and does not need a copy of the state after the method returns, it won't need to take another reservation. And if it does need to keep the state after the method returns, it is simple to take a new reservation.
  3. When creating a new SignedState, do not pass it to other methods or parts of the system with an implicit reference, always ensure that an explicit reservation is held before passing a SignedState to other parts of the code.
  4. It is NEVER thread safe for threads to read from the same ReservedSignedState instance concurrently with another thread calling ReservedSignedState.close(). a. In multithreaded environments, prefer to create a new ReservedSignedState for each thread that needs to read from the state, or b. Use the SignedStateReference and/or SignedStateMap utility objects, which provide thread-safe access and management of SignedState objects.
  5. When using any API that requires a reason to be provided when taking a new reservation on a signed state, ensure that the reason is sufficiently unique so that an engineer debugging a reference count exception can unambiguously find the code that is responsible for the reservation by searching for the reason string.
  6. Setting configuration state.debugStackTracesEnabled = true provides extra information in the logs when a reference count exception occurs. This can be useful for debugging reference count issues, but it is critical that this setting is NEVER enabled in a production environment (this feature has non-trivial impacts on performance).