Because transactions are identified by their hashes. Transaction hash is calculated on all the fields of the transaction. After transaction is signed, you can't modify it without changing the hash, and if you do that before it is mined, the network takes it as a different transaction.
When a transaction creates a contract, the contract address is stored in the Receipt. How would you add this data to the transaction struct
without changing its hash? You couldn't. The only way to seal the result of the transaction is to create another struct
and store it there. This is what Receipts
are, its the output
of the transaction, a very different concept, while Transaction
data being the input
.
In short, the decision to design things this way was correct.
BTW, transactions are not stored in the block header, transactions are stored in a separate trie. Only the hash of all transactions of the block is kept in the header.