Repository navigation
fix: validate chunk order and identity when deserializing chunked transactions - #2736
danielmarv wants to merge 2 commits into
Conversation
…nsactions Transaction.from_bytes() now rejects a TransactionList for FileAppendTransaction or TopicMessageSubmitTransaction unless its chunk groups share one payer, have strictly increasing valid starts and, for topic messages, carry chunk info matching the chunk sequence. The checks are derived from each chunk group's body rather than from the transaction IDs collected in first-seen order, which always matched the input order and let reordered chunk groups pass. from_bytes() now only falls back to parsing a single Transaction when the bytes do not decode to a non-empty TransactionList, so validation errors reach the caller instead of being replaced by an unrelated parse error. Signed-off-by: Ntege Daniel <danientege785@gmail.com>
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## main #2736 +/- ##
==========================================
+ Coverage 95.68% 95.70% +0.01%
==========================================
Files 169 169
Lines 11080 11119 +39
==========================================
+ Hits 10602 10641 +39
Misses 478 478 🚀 New features to boost your workflow:
|
aceppaluni
left a comment
There was a problem hiding this comment.
Should we add a regression test using a real serialized single Transaction that is also successfully decoded as a non-empty TransactionList?
Since protobuf parsing doesn't necessarily distinguish these two wire formats, checking only transaction_list.transaction_list may incorrectly classify the input and skip the single-transaction fallback.
What do you think?
|
Thanks @aceppaluni test_from_bytes_accepts_single_transaction_bytes already covers a real serialized signedTransactionBytes transaction. I've added a regression test for the legacy bodyBytes + sigMap format, plus one showing a deprecated body transaction is rejected with a ValueError. |
Description:
Transaction.from_bytes()accepted aTransactionListfor a chunked transaction (FileAppendTransaction,TopicMessageSubmitTransaction) whose chunk groups were reordered or belonged to different chunked transactions. The restored transaction then re-serialized and executed the chunks in input order: file contents were appended out of order, and topic message chunks were submitted out of sequence.transactionValidStartstrictly increases from one chunk group to the next;consensusSubmitMessageonly:chunkInfo.numberis the chunk's 1-based position,chunkInfo.totalequals the number of chunk groups, andchunkInfo.initialTransactionIDequals the first chunk's transaction ID.from_bytes()only falls back to the singleTransactionformat when the bytes do not decode to a non-emptyTransactionList. Validation errors now reach the caller as aValueErrorwith the real cause, instead of being replaced by an unrelated parse error._process_transaction_list_bytes()into_parse_transaction_list()and_process_transaction_list(). No public API changes.Related issue(s):
Fixes #2710
Notes for reviewer:
transaction_idsis collected in first-seen input order, and_validate_transaction_pairs()builds its expected layout from it, so a reordered list always matched itself. The new checks read each chunk group's owntransactionIDandchunkInfoinstead.TopicMessageSubmitTransactionspace chunk valid starts 1ns apart, but the JSFileAppendTransactionuses a configurablechunkInterval(default 10ns). Neither carries nanos overflow into seconds, so valid starts are compared as(seconds, nanos).chunkInfofor a single chunk, while JS setstotal=1, number=1. Both are accepted. A lone chunk of a larger message (e.g.total=2) is now rejected as incomplete.FileAppendTransactioncarries no chunk count, so a list with its last chunk(s) removed cannot be detected. Topic messages are covered bychunkInfo.total.test_validate_transaction_bodies_chunk_transactionandtest_validate_transaction_bodies_chunk_transaction_mutiple_node_idsused different payers (0.0.2and0.0.3);test_validate_transaction_bodies_for_chunk_file_append_txandtest_validate_transaction_bodies_for_chunk_message_submit_txbuilt chunk IDs withTransactionId.generate(), which subtracts a random 5–8s, so the second chunk was often earlier than the first. The topic test also gave both chunksnumber=1and unrelatedinitialTransactionIDs.transaction_idsannotation in_process_transaction_list()(list[Transaction]→list[TransactionId]).tests/unit/chunked_transaction_from_bytes_test.py(66 cases) tests throughTransaction.from_bytes()for both types, with one and two nodes:chunkInfo.number/total, mismatchedinitialTransactionID, missingchunkInfoand an incomplete topic message are rejected with a specific message. All 34 rejection cases fail againstmain.transaction_freeze_and_bytes_test.pyfor the singleTransactionfallback (previously untested) and for aTransactionListvalidation error reaching the caller.uv run pytest tests/unit: 3404 passed.gitleaks,end-of-file-fixer,trailing-whitespace,ruff-check,ruff-format,bandit) pass.Checklist