diff --git a/haskoin-store-data.cabal b/haskoin-store-data.cabal
--- a/haskoin-store-data.cabal
+++ b/haskoin-store-data.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           haskoin-store-data
-version:        1.7.0
+version:        1.8.0
 synopsis:       Data for Haskoin Store
 description:    Please see the README on GitHub at <https://github.com/jprupp/haskoin-store#readme>
 category:       Bitcoin, Finance, Network
diff --git a/src/Haskoin/Store/Data.hs b/src/Haskoin/Store/Data.hs
--- a/src/Haskoin/Store/Data.hs
+++ b/src/Haskoin/Store/Data.hs
@@ -1095,33 +1095,33 @@
       deleted = t.deleted,
       rbf = t.rbf,
       timestamp = t.timestamp,
-      txid = txHash t.tx,
+      txid = TxHash (doubleSHA256 witless),
       inputs = ins,
       outputs = outs,
-      size =
-        fromIntegral $
-          B.length $
-            runPutS $
-              serialize t.tx,
-      weight =
-        let b = B.length $ runPutS $ serialize witless
-            x = B.length $ runPutS $ serialize t.tx
-         in fromIntegral $ b * 3 + x,
+      size = fromIntegral (B.length full),
+      weight = fromIntegral (B.length witless * 3 + B.length full),
       fee =
         if any isCoinbase ins
           then 0
           else inv - outv
     }
   where
-    ins = zipWith f [0 ..] t.tx.inputs
-    witless =
-      let Tx {..} = t.tx
-       in Tx {witness = [], ..}
+    -- Serialize once with the witness and once without it, and only once
+    -- if there is no witness, when both are the same bytes. The id of the
+    -- transaction is the hash of the bytes without witness, as 'txHash'
+    -- computes it.
+    full, witless :: ByteString
+    full = runPutS (serialize t.tx)
+    witless
+      | hasWitness t.tx =
+          let Tx {..} = t.tx
+           in runPutS (serialize Tx {witness = [], ..})
+      | otherwise = full
+    ins = zipWith3 f [0 ..] t.tx.inputs (t.tx.witness <> repeat [])
     inv = sum (map (.value) ins)
     outs = zipWith g [0 ..] t.tx.outputs
     outv = sum $ map (.value) outs
-    ws = take (length t.tx.inputs) $ t.tx.witness <> repeat []
-    f n i = toInput net ctx i (IntMap.lookup n t.prevs) (ws !! n)
+    f n i w = toInput net ctx i (IntMap.lookup n t.prevs) w
     g n o = toOutput net ctx o $ IntMap.lookup n t.spenders
 
 fromTransaction :: Transaction -> TxData
diff --git a/test/Haskoin/Store/DataSpec.hs b/test/Haskoin/Store/DataSpec.hs
--- a/test/Haskoin/Store/DataSpec.hs
+++ b/test/Haskoin/Store/DataSpec.hs
@@ -161,6 +161,19 @@
         p2wpkh = "0014751e76e8199196d454941c45d1b3a323f1433bd6"
         -- OP_HASH256, a push of 32 bytes, OP_EQUAL.
         hashLock = "aa20bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb87"
+    it "computes the id, size, weight and witnesses of the transaction" $
+      forAll (arbitraryTxData ctx) $ \td ->
+        let t = toTransaction btc ctx td
+            len :: Tx -> Int
+            len = B.length . runPutS . serialize
+            witless = let Tx {..} = td.tx in Tx {witness = [], ..}
+            ws = take (length td.tx.inputs) (td.tx.witness <> repeat [])
+         in (t.txid, t.size, t.weight, map (.witness) t.inputs)
+              `shouldBe` ( txHash td.tx,
+                           fromIntegral (len td.tx),
+                           fromIntegral (len witless * 3 + len td.tx),
+                           ws
+                         )
     it "gives a SegWit output its address on Bitcoin" $
       outputJson btc p2wpkh
         `shouldBe` [ json
