Understanding SoftLocking


(Sean Zhang) #1

Trying to understand the behavior of softlocking, I thought once a transaction acquires a lock on a state via
serviceHub.vaultService.softLockReserve(txBuilder.lockId, setOf(aStateRef))
, any other transactions trying to consume the same state will be blocked until the lock is released, much like the usual RDBMS.
But our tests show that the competing transactions get the StateNotAvailableException instead. Is that by design? Of course, if we don’t use soft locking in this case, the Notary will throw the exception for double spend.
So it seems that with and without softlocking, the end result is similar - both result in exceptions. The difference may be in performance as per the doc https://docs.corda.net/soft-locking.html?highlight=softlock.
As for the user (RPC client), what is the best practice? try/catch and rerun the flow?

Thanks.

\Sean


(Jose Coll) #2

Hi Sean,
Yes - your understanding is mostly correct.
However, if there are no available unconsumed states in the vault, rather than block, we perform an automatic exponential back-off and retry (100, 200, 300, 400, 500 msec). After this, we return a StatesNotAvailableException which you may use to determine further action in your application.
Soft Locking effectively provides an early detection of an attempt to double spend, which will ultimately be captured by the Notary (as you correctly point out).
Note also that all soft locks are automatically relinquishes upon flow termination (whether successful or not).
From an RPC client, it is the application developers responsibility to release soft locks (unless calling to invoke a Flow).
Regards,
Jose


(Sean Zhang) #3

Thanks, Jose for the clarification.

As for the retry (100, 200, 300, 400, 500 msec), that seems to allow the competing transaction to “block” up to 2.5 secs prior to exception. But the test results below seem to suggest that the exception is thrown immediately. Three transactions trying to consume the same stateRef simultaneously; one of them was successful and other two failed. All seem to have happened within a second.
Did I miss anything?

Thanks.

\Sean

I 09:49:57 [Test worker] flow.MasterAgreementCreateFlowTest_Mock.MasterAgreement Create to Parallel Contract Proposes - Success: SignedTransaction(id=D7F6227C02A8CC84674674BE34D7E633CF63EB006DD8327B8D0BEFB9E625543E)
E 09:49:57 [Test worker] flow.MasterAgreementCreateFlowTest_Mock.MasterAgreement Create to Parallel Contract Proposes - Attempted to reserve [5AC1BA2A3730DE390E03796C03C8F78B1103E0805A9BD716E6771213367DFDFA(1)] for cffe4cc4-1413-4f0e-9a70-5bd67a6eb1fd but only 0 rows available
E 09:49:57 [Test worker] flow.MasterAgreementCreateFlowTest_Mock.MasterAgreement Create to Parallel Contract Proposes - Attempted to reserve [5AC1BA2A3730DE390E03796C03C8F78B1103E0805A9BD716E6771213367DFDFA(1)] for 7ae0a093-81ed-4a9e-af43-0421a10d2ff5 but only 0 rows available