Assuming SQL Server here, since that looks a lot like SQL Server syntax:
Preferably, you should also use SAVE TRAN
so you can treat the procedure as its own unit of work and let the caller choose whether or not to rollback the entire transaction (as opposed to only rolling back the work in this particular block). Remus Rusanu wrote an article about that a while back.
Putting that aside for the moment, you need to save the error immediately after you catch it and then re-raise it after rolling back (normally with some additional info):
CREATE PROCEDURE xyz [params]
AS
BEGIN
BEGIN TRY
BEGIN TRAN
-- Do the work
COMMIT
END TRY
BEGIN CATCH
DECLARE
@Error int,
@Severity int,
@Message varchar(4000)
SELECT
@Error = ERROR_NUMBER(),
@Severity = ERROR_SEVERITY(),
@Message = ERROR_MESSAGE()
ROLLBACK
RAISERROR('Procedure xyz: %d: %s', @Severity, 1, @Error, @Message)
END CATCH
END