A question about full nodes, lightweight nodes and merkle trees What is the purpose of full nodes storing merkle roots? Why don't they save the transactions only? The hashes could be calculated only when a lightnode asks for them and the merkle roots could be saved only be the lightnodes. Am I missing something here?
I suspect you are confusing merkle roots and merkle trees.

A merkle tree is the binary tree of hashes. The leaves are individual transactions, which are hashed, and then the hashes hashed together until only one hash remains. That remaining hash is the merkle root. A merkle branch is a particular path down the merkle tree from the merkle root to a transaction.

Full nodes store the merkle root because it is part of the block header. The block header contains the merkle root so that the block hash itself will also commit to the transactions contained within the block. While the merkle root itself isn't generally used elsewhere, as part of the block header, it frequently needs to be sent out to other nodes which are downloading blocks. It is expensive to have to recompute the merkle root every time, so instead we just keep it so that blocks can be sent out quickly.

Furthermore, by storing the complete block header, when the transactions themselves are discarded in pruning, the block headers are kept and so that the header chain is still tracked. Without the transactions, it would not be possible to verify this header chain again if the merkle root were not being stored.

Full nodes do not store the entire merkle tree or any merkle branches. These are unnecessary for normal operation. When a SPV client asks for a merkle branch, it is computed on the fly.