Skip to content

python: zap_py EVM helpers (Address, Hash, Signature, Bloom)#2

Open
abhicris wants to merge 2 commits intoluxfi:mainfrom
kcolbchain:zap-py-evm
Open

python: zap_py EVM helpers (Address, Hash, Signature, Bloom)#2
abhicris wants to merge 2 commits intoluxfi:mainfrom
kcolbchain:zap-py-evm

Conversation

@abhicris
Copy link
Copy Markdown

Summary

Follow-up to #1. Ports the EVM helpers I called out as not-yet-done in that PR.

  • New python/zap_py/evm.py — immutable fixed-width values: Address (20), Hash (32), Signature (65), Bloom (256). Each has .from_hex() (0x / 0X tolerated), .hex(), .is_zero(), .bytes, bytes-equality, and hashing.
  • Reader extensions on Object: .address(off), .hash(off), .signature(off), plus .address_slice(off) / .hash_slice(off) returning a zero-copy memoryview.
  • Reader extensions on List: .address(i), .hash(i) for lists of fixed-width elements.
  • Builder extensions on ObjectBuilder: .set_address, .set_hash, .set_signature. Each accepts either the typed value or raw bytes; mismatched lengths raise ValueError.
  • 13 new tests: hex roundtrip with case-insensitive prefix, invalid-length rejection, zero detection, single-field roundtrip, zero-copy slice view, raw-bytes-input acceptance, address/hash list typed access, bytes equality.

Cross-language parity

Third Go-built fixture proves wire compatibility for an EVM-typed message:

go run ./python/testdata/gen_evm_fixture.go > /tmp/zap_evm_fixture.bin
ZAP_GO_EVM_FIXTURE=/tmp/zap_evm_fixture.bin python -m pytest python/tests/test_evm.py::test_evm_go_fixture_interop

The fixture exercises SetAddress / SetHash / SetSignature plus a typed Address list — all read back identically through zap_py.

Stack

This PR is stacked on top of #1 (the base zap_py reader/builder). GitHub will rebase/squash cleanly once #1 lands; until then the diff is best read as ${additions} on top of that branch.

Test plan

  • cd python && .venv/bin/pytest tests/ — 24 passed, 2 skipped (interop fixtures gated on env vars)
  • ZAP_GO_EVM_FIXTURE=... pytest tests/test_evm.py::test_evm_go_fixture_interop — passed
  • go test ./... — full Go suite still green

Abhishek Krishna added 2 commits April 27, 2026 17:41
Adds python/zap_py — a pure-stdlib (no deps, py>=3.8) reader and
builder that's wire-compatible with the Go reference. Lets non-Go
peers (AI agents, ops scripts, FHE clients) speak ZAP without
leaving Python.

Read: parse() returns a Message backed by a memoryview; .bytes_view()
exposes zero-copy slices.
Build: Builder/ObjectBuilder/ListBuilder mirror builder.go method
for method, including the deferred-write trick for text/bytes so
relative offsets match the Go encoder byte for byte.

Coverage: header validation, all scalar widths (bool, u8/16/32/64,
i8/16/32/64, f32/f64), text, bytes, nested objects, lists of
u8/u32/u64/objects/raw bytes, null pointers, flag bits.

Bidirectional fixtures prove parity:
- python/testdata/gen_fixture.go      → emits a Go-built message
- python/testdata/gen_python_fixture.py → emits a Python-built one
- python/tests/test_roundtrip.py::test_go_fixture_interop reads
  the Go fixture from Python (skipped unless ZAP_GO_FIXTURE is set)
- python_interop_test.go::TestPythonFixture reads the Python fixture
  from Go (skipped unless ZAP_PYTHON_FIXTURE is set)

Both fixtures use identical schemas; output is byte-identical
except for the embedded text payload.

go.sum gains the missing luxfi/mdns line that `go test ./...` already
requires (fixes a tidy-state issue surfaced while wiring up the new
Go interop test).

Not ported (yet): EVM helpers, MCP bridge, mDNS node, schema DSL.
Reader+builder is enough to interop with any Go ZAP service that
publishes a fixed schema; higher-level helpers can follow as Python
use cases land.
Follow-up to luxfi#1. Adds the EVM helpers called out as not-yet-ported in
that PR: fixed-width Address (20), Hash (32), Signature (65), Bloom
(256), with hex parsing, zero detection, and reader/builder methods
on Object, ObjectBuilder, and List that mirror evm.go.

New module: python/zap_py/evm.py
  - _FixedBytes base + Address / Hash / Signature / Bloom
  - .from_hex() (0x/0X tolerated), .hex(), .is_zero(), .bytes
  - bytes-equality so Address == bytes(...) works
  - ZERO_ADDRESS / ZERO_HASH constants
  - top-level address_from_hex / hash_from_hex helpers

Reader extensions (reader.py):
  - Object.address / .hash / .signature
  - Object.address_slice / .hash_slice (zero-copy memoryview)
  - List.address / .hash for lists of fixed-width elements

Builder extensions (builder.py):
  - ObjectBuilder.set_address / .set_hash / .set_signature
  - All accept either the typed value or raw bytes; reject mismatched
    lengths with a clean ValueError

Tests (13 new): hex roundtrip (case-insensitive prefix), invalid-length
rejection, zero detection, single-field roundtrip, zero-copy slice
view, raw-bytes-input acceptance, address-list and hash-list typed
access, bytes equality.

Cross-language parity: python/testdata/gen_evm_fixture.go emits a
Go-built EVM-typed message; tests/test_evm.py::test_evm_go_fixture_interop
parses it from Python under ZAP_GO_EVM_FIXTURE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant