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.
- 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. ASignedState
passed directly into a method is only guaranteed to be valid until the method returns. b. If aSignedState
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 viaReservedSignedState 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. - If an object of type
ReservedSignedState
is passed into a method, it is the responsibility of the method to guarantee thatReservedSignedState.close()
is eventually called. a. If possible, use aReservedSignedState
in a try-with-resources block. b. Avoid using@Nullable ReservedSignedState
parameters. As a pattern, it is better to pass a non-nullReservedSignedState
wrapped aroundnull
. c. In general, prefer passing aSignedState
into a method instead of aReservedSignedState
. 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. - 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 aSignedState
to other parts of the code. - It is NEVER thread safe for threads to read from the same
ReservedSignedState
instance concurrently with another thread callingReservedSignedState.close()
. a. In multithreaded environments, prefer to create a newReservedSignedState
for each thread that needs to read from the state, or b. Use theSignedStateReference
and/orSignedStateMap
utility objects, which provide thread-safe access and management ofSignedState
objects. - 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.
- 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).