feat: add UtxoProcessor event listeners#20
Conversation
WASM parity: UtxoProcessor addEventListener/removeEventListener API surface (dispatch TBD) Tests: cargo fmt --all; cargo clippy -- -D warnings; ./build-dev; pytest tests/unit -v
WASM parity: wallet/core/src/wasm/utxo/processor.rs (multiplexer dispatch) Tests: cargo fmt --all Tests: cargo clippy -- -D warnings Tests: ./build-dev Tests: source env/bin/activate && pytest tests/unit -v Tests: source env/bin/activate && pytest tests/integration -v
WASM parity: wallet/core/src/wasm/utxo/processor.rs (Events::to_js_value flattening; start double-call behavior) Tests: cargo fmt --all Tests: cargo clippy -- -D warnings Tests: ./build-dev Tests: source env/bin/activate && pytest tests/unit -v Tests: source env/bin/activate && pytest tests/integration -v
WASM parity: wallet/core/src/wasm/utxo/processor.rs (event listeners) Tests: cargo fmt --all Tests: cargo clippy -- -D warnings Tests: source env/bin/activate && pytest tests/unit -v
WASM parity: wasm/wallet/core/src/wasm/utxo/processor.rs@1a2f98a
WASM parity: wasm/wallet/core/src/wasm/utxo/processor.rs@1a2f98a
WASM parity: wasm/wallet/core/src/wasm/utxo/processor.rs@1a2f98a
WASM parity: wasm/wallet/core/src/wasm/utxo/processor.rs@1a2f98a
WASM parity: wasm/wallet/core/src/wasm/utxo/processor.rs@1a2f98a (listener overloads) Tests: cargo fmt --all; cargo clippy -- -D warnings; source env/bin/activate && pytest tests/unit -v
WASM parity: docs only Tests: cargo fmt --all; cargo clippy -- -D warnings; source env/bin/activate && pytest tests/unit -v
There was a problem hiding this comment.
@elldeeone Again, thank you for your continued work here! This callback functionality is fun to work on, much deeper than simple standard wrappers.
Here are comments from first pass through. One thing to change and two where I'm curious for your thoughts. May result in changes depending on what you think.
| } | ||
| } | ||
|
|
||
| fn parse_event_targets(value: Bound<'_, PyAny>) -> PyResult<Vec<EventKind>> { |
There was a problem hiding this comment.
@elldeeone The following probably could have been tagged to a different line of code but this fn made me think about it.
What do you think about the following?
- Introduce a Python-exposed enum that wraps EventKind (e.g.
UtxoProcessorEventKindor something like that). - Implement PyO3's
FromPyObjecttrait for the enum so that it can be extracted from str or enum variant on the Rust side. - For add/remove listener methods - the
eventparameter can then be passed asstr,UtxoProcessorEventKindvariant,list[str | UtxoProcessorEventKind], (and maybe others if I'm missing anything).
There is something similar in place for RpcClient event types:
PyNotificationEventprovides enum with all event types to Python developers.- It can be extracted from pyobject as str or variant (see
FromPyObjectimpl here). - RpcClient
add_event_listener()acceptseventparameter asPyNotificationEvent(link). This allows user to pass event as str or enum variant. Different here is that a list of events is not supported
If we added a wrapper enum for UtxoProcessor, it could probably use one of the wrap enum macros from macros.rs. While on the RpcClient side it required a different implementation because of some RK native enum nesting (iirc).
The benefit of adding a wrapper enum is that it gives Python developers a static list of supported event types.
I don't feel too strongly about this at the moment but while work is actively being done here perhaps it's worth doing for parity with python RpcClient event passing. Curious what you think
There was a problem hiding this comment.
@smartgoo Thanks for the suggestion and for laying it out so clearly. I agree with your direction here, and your comparison to RpcClient helped shape my final approach.
I’ve implemented a Python-exposed UtxoProcessorEvent enum, FromPyObject extraction from both str and enum variant, and listener target parsing for str | UtxoProcessorEvent | Sequence[str | UtxoProcessorEvent] in both add_event_listener and remove_event_listener.
I also updated stubs/docs and tests. I ended up taking the explicit enum/impl route here instead of the macro, mainly to keep the extraction behaviour and event surface explicit. Do you think this looks ok?
There was a problem hiding this comment.
@elldeeone I think the primary benefit of a Python wrapper enum over the RK native enum (via one of the macros or otherwise) is - the compiler ensures all enum variants are present in the Python enum.
That said I'm ok with this approach of defining explicitly. Not like it rk native enum will change often. Just curious why this approach instead of one the macros? If there is missing functionality, an issue, etc.
There was a problem hiding this comment.
@elldeeone BTW just the one question in comment above and we should be able to merge this after. Everything else looks good!
There was a problem hiding this comment.
@smartgoo Yeah true, I agree the macro path gives compile-time coverage if RK enum variants change.
I went explicit in this PR mainly to avoid blowing out scope while we were still settling listener parsing/validation behaviour. In hindsight, I suppose it's not that much though. If you’d prefer, I’m happy to switch this enum to wrap_unit_enum_for_py! here before merge just lmk.
There was a problem hiding this comment.
@elldeeone All good, we can move it to macro sometime soon. Merging shortly!
Extract shared internal PyCallback helper for RpcClient and UtxoProcessor event listener dispatch/removal. WASM parity: no API behavior change; keep UtxoProcessor/RpcClient addEventListener semantics aligned with wallet/core/src/wasm/utxo/processor.rs@1a2f98a
Expose UtxoProcessorEvent to Python and accept str | enum | sequence[str|enum] in UtxoProcessor listener target parsing. WASM parity: align Python UtxoProcessor listener target surface with wallet/core/src/wasm/notify.rs and wallet/core/src/wasm/utxo/processor.rs@1a2f98a
Prevent empty-string listener targets from falling through iterable parsing and silently no-oping. Add regression tests for add/remove listener empty target handling. WASM parity: preserve event-target validation behavior while extending Python target typing for UtxoProcessor listeners
# Conflicts: # docs/CHANGELOG.md
|
@elldeeone Merged, thank you! |
|
@smartgoo thanks for the review! |
Summary:
UtxoProcessorevent listeners:add_event_listener,remove_event_listener,remove_all_event_listeners.processor.multiplexer().channel()to Python callbacks; start dispatcher beforeUtxoProcessor.start(), stop afterUtxoProcessor.stop().{"type": "<kebab>", "data": <obj|None>}; tx-record events flattened to match WASMEvents::to_js_value().Tests:
Notes:
UtxoProcessorEventType(wallet/core/src/wasm/notify.rs@rusty-kaspa@1a2f98a), plus"*"and"all"alias.callback(*args, event, **kwargs); callback errors logged; dispatch continues.examples/transactions/utxo_context_listener.pypyo3-stub-gencan’t express the overload cleanly (it emitscallback: Optional[...] = None, which implies invalid calls when targets are provided). We post-processkaspa.pyito inject@typing.overloadentries so type-checkers/IDEs reflect the real call patterns; typing-only, no runtime behaviour change.