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. ![]()