karask / python-bitcoin-utils

Library to interact with the Bitcoin network. Ideal for low-level learning and experimenting.
MIT License
262 stars 99 forks source link

Serialization and Deserialization inconsistency in Script Object with hex data #68

Closed ongrid closed 2 months ago

ongrid commented 2 months ago

After dumping Script object into a hex string and loading it back, the script unexpectedly changes. This typically leads to following execution tracebacks:

mandatory-script-verify-flag-failed (Opcode missing or not understood)
[0200000000010127722ee3bf97be35ed509b8e439cef19b19468e6d3220e4c24862e8b9ef178290000000000ffffffff025e01000000000000225120a736f28008423065db7178f464e9ea019d44d395f4a3ea48705ecb77e9295c3d32cf030000000000225120a736f28008423065db7178f464e9ea019d44d395f4a3ea48705ecb77e9295c3d034091625ee24b8a186aab068f0fa072e10d4e43efb9161c773bc1b6f5b63063549aac9bb08fb530ea4f77136836385cb67e5008d32cf0e5303d4acb52579552baf3fd6d0120c29ab360da10dbcfe26000e13232911bcedc83bfd4c758ad7eaaed5f5ef8ebcaac0063036f7264010117746578742f68746d6c3b636861727365743d7574662d38004d25013c21444f43545950452068746d6c3e3c68746d6c3e3c626f64793e3c736372697074207372633d222f636f6e74656e742f356465343335333961366636316131363635323331376462346530336333353963363666396531383132613165333136303032306164643738363037353264336930223e3c2f7363726970743e3c7363726970743e636f6e73742064657461696c73496e4c666f203d207b69643a202233393239222c206c696e6b3a20226767517431374764222c2062673a202249766f7279222c207374616e643a202254657272615768697465222c206a6164653a2022416d626572222c206f7574736964653a2022566f69646564222c20746f703a202250696e6b526f7365227d3b3c2f7363726970743e3c2f626f6479083c2f68746d6c3e6821c0c29ab360da10dbcfe26000e13232911bcedc83bfd4c758ad7eaaed5f5ef8ebca00000000]

Reproduction

privkey_x_only_hex = "de" * 31
content = "deadbeef" * 100
script = Script(
    [
        privkey_x_only_hex,
        "OP_CHECKSIG",
        "OP_0",
        "OP_IF",
        content,
        "OP_ENDIF",
    ]
)
hex_dump_one = script.to_hex()
recovered_script = script.from_raw(hex_dump_one)
hex_dump_two = recovered_script.to_hex()

assert len(script.script) == len(recovered_script.script)
assert hex_dump_two == hex_dump_one

Variables state after execution:

hex_dump_one = '1fdededededededededededededededededededededededededededededededeac00634d0190deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef68'

hex_dump_two = '1fdededededededededededededededededededededededededededededededeac00634d01904cdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbe4cb1deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef68'

You can notice the difference visually.

I'd suggest the way the Script object stores data: instead of a dictionary of tokens, use a hex string. This would make it easier to dump, load and inspect its assembly without additional parsing/processing.

karask commented 2 months ago

Hi @ongrid

Just committed v0.6.7 that fixes this issue. I am closing this but let me know if get any more issues.