For the past week, I’ve been trying to debug a rather difficult binding tester failure in my Tokio Rust bindings.
@PierreZ has also encountered a similar error in his Rust bindings.
At a high level, what seems to be happening is that in Rust binding tester I am seeing a transaction succeed, whereas in Python the transaction is failing. Binding tester generates the following error.
Incorrect result:
rust - ('tester_output', 'workspace', None, 7.77163468821456e-132, True, (SingleFloat(2.781151311691776e+16),)) = b'\x01ERROR\x00\x014436\x00'
python - None
Incorrect result:
rust - ('tester_output', 'stack', 596, 34252) = b'\x01RESULT_NOT_PRESENT\x00'
python - ('tester_output', 'stack', 596, 34252) = b'\x01\x01ERROR\x00\xff\x011020\x00\xff\x00'
The sequence of instructions that is causing this issue is as follows.
34224. 'WAIT_FUTURE'
34225. 'NEW_TRANSACTION'
34226. 'PUSH' 4436
34227. 'ON_ERROR'
34228. 'WAIT_FUTURE'
34229. 'NEW_TRANSACTION'
34230. 'SET_READ_VERSION'
34231. 'PUSH' ...
34232. 'SET'
34233. 'PUSH' ...
34234. 'PUSH' ...
34235. 'WRITE_CONFLICT_RANGE'
[...]
34250. 'GET_KEY'
34251. 'WAIT_FUTURE'
34252. 'COMMIT'
34253. 'WAIT_FUTURE'
34254. 'RESET'
34255. 'NEW_TRANSACTION'
At instruction 34229
a new transaction is setup whose read version gets modified (34230
) to the version stored in the state machine. This transaction then commits in instruction 34252
causing an error in Python but succeeds in Rust. I’ve verified the inputs to intermediary SET
, WRITE_CONFLICT_RANGE
and GET_KEY
, and they are similar.
I also tried to setup tracing at the C library level. C level trace logs for the transaction at instruction 34229
is here: trace-py.json and trace-rs.json
As you can see from the trace logs, the main difference seems to be that in case of Rust, I am seeing that self-conflicting transactions (prefix \xFF/SC/..
) gets inserted and transaction succeeds. However in case of Python, these self-conflicting transactions are missing.
Now, if I were to surgically disable instruction 34230. 'SET_READ_VERSION'
by modifying Rust binding tester and also Python tester.py
, then transaction 34229
succeeds in both Rust and Python.
The C level trace logs are here: trace-py-34230-disabled.json and trace-rs-34230-disabled.json.
Another observation from the above trace logs is that even when the transaction 34229
succeeds, Python binding tester is not generating self-conflicting transaction, while Rust binding tester does. I am not sure why that is the case.
The seed that causing this issue is 4238495939
and it is happening at num-op 430
. I use a slightly modified version of binding tester (since I don’t have support for versionstamp v1). You can use the binding tester that is here if you would like to generate the full sequence of instructions.
At num-op 1000
, SET_READ_VERSION
instruction is generated 4 times. Its only the second SET_READ_VERSION
at 34230
that is causing the issue.
I would really appreciate help in figuring out what might be wrong and how I can fix it.