diff --git a/Network/Haskoin/Block/Types.hs b/Network/Haskoin/Block/Types.hs
--- a/Network/Haskoin/Block/Types.hs
+++ b/Network/Haskoin/Block/Types.hs
@@ -25,7 +25,7 @@
 import Data.Word (Word32)
 import Data.Binary (Binary, get, put)
 import Data.Binary.Get (getWord32le)
-import Data.Binary.Put (putWord32le)
+import Data.Binary.Put (Put, putWord32le)
 import Data.String (IsString, fromString)
 import Data.String.Conversions (cs)
 import Text.Read (readPrec, parens, lexP, pfail)
@@ -63,7 +63,7 @@
 
     put (Block h cb txs) = do
         put h
-        put $ VarInt $ fromIntegral $ (length txs) + 1
+        put $ VarInt $ fromIntegral $ length txs + 1
         put cb
         forM_ txs put
 
@@ -92,11 +92,11 @@
     put = put . getBlockHash
 
 instance FromJSON BlockHash where
-    parseJSON = withText "Block hash" $ \t -> do
-        maybe mzero return $ BlockHash <$> (bsToHash256 =<< decodeHex (cs t))
+    parseJSON = withText "Block hash" $ \t ->
+        maybe mzero return $ hexToBlockHash $ cs t
 
 instance ToJSON BlockHash where
-    toJSON h = String $ cs $ encodeHex $ getHash256 $ getBlockHash h
+    toJSON = String . cs . blockHashToHex
 
 blockHashToHex :: BlockHash -> ByteString
 blockHashToHex (BlockHash h) = encodeHex $ BS.reverse $ getHash256 h
@@ -193,12 +193,15 @@
       where
         repList (VarInt c) = replicateM (fromIntegral c) get
 
-    put (GetBlocks v xs h) = do
-        putWord32le v
-        put $ VarInt $ fromIntegral $ length xs
-        forM_ xs put
-        put h
+    put (GetBlocks v xs h) = putGetBlockMsg v xs h
 
+putGetBlockMsg :: Word32 -> BlockLocator -> BlockHash -> Put
+putGetBlockMsg v xs h = do
+    putWord32le v
+    put $ VarInt $ fromIntegral $ length xs
+    forM_ xs put
+    put h
+
 -- | Similar to the 'GetBlocks' message type but for retrieving block headers
 -- only. The response to a 'GetHeaders' request is a 'Headers' message
 -- containing a list of block headers pertaining to the request. A maximum of
@@ -228,11 +231,7 @@
       where
         repList (VarInt c) = replicateM (fromIntegral c) get
 
-    put (GetHeaders v xs h) = do
-        putWord32le v
-        put $ VarInt $ fromIntegral $ length xs
-        forM_ xs put
-        put h
+    put (GetHeaders v xs h) = putGetBlockMsg v xs h
 
 -- | 'BlockHeader' type with a transaction count as 'VarInt'
 type BlockHeaderCount = (BlockHeader, VarInt)
@@ -279,8 +278,8 @@
     size = fromIntegral $ c `shiftR` 24
     neg  = (c .&. 0x00800000) /= 0
     wrd  = c .&. 0x007fffff
-    res | size <= 3 = (toInteger wrd) `shiftR` (8*(3 - size))
-        | otherwise = (toInteger wrd) `shiftL` (8*(size - 3))
+    res | size <= 3 = toInteger wrd `shiftR` (8*(3 - size))
+        | otherwise = toInteger wrd `shiftL` (8*(size - 3))
 
 -- | Encode an Integer to the compact number format used in the difficulty
 -- target of a block.
@@ -295,5 +294,5 @@
        | otherwise = posi `shiftR` (8*(s1 - 3))
     (s2,c2) | c1 .&. 0x00800000 /= 0  = (s1 + 1, c1 `shiftR` 8)
             | otherwise               = (s1, c1)
-    c3 = fromIntegral $ c2 .|. ((toInteger s2) `shiftL` 24)
+    c3 = fromIntegral $ c2 .|. (toInteger s2 `shiftL` 24)
 
diff --git a/Network/Haskoin/Constants.hs b/Network/Haskoin/Constants.hs
--- a/Network/Haskoin/Constants.hs
+++ b/Network/Haskoin/Constants.hs
@@ -166,7 +166,7 @@
         }
     , getMaxBlockSize = 1000000
     , getMaxSatoshi = 2100000000000000
-    , getHaskoinUserAgent = "/haskoin:0.2.0/"
+    , getHaskoinUserAgent = "/haskoin:0.3.0/"
     , getDefaultPort = 8333
     , getAllowMinDifficultyBlocks = False
     , getPowLimit = fromIntegral (maxBound `shiftR` 32 :: Word256)
@@ -234,7 +234,7 @@
         }
     , getMaxBlockSize = 1000000
     , getMaxSatoshi = 2100000000000000
-    , getHaskoinUserAgent = "/haskoin-testnet:0.2.0/"
+    , getHaskoinUserAgent = "/haskoin-testnet:0.3.0/"
     , getDefaultPort = 18333
     , getAllowMinDifficultyBlocks = True
     , getPowLimit = fromIntegral (maxBound `shiftR` 32 :: Word256)
diff --git a/Network/Haskoin/Crypto.hs b/Network/Haskoin/Crypto.hs
--- a/Network/Haskoin/Crypto.hs
+++ b/Network/Haskoin/Crypto.hs
@@ -138,22 +138,26 @@
 , deriveMSAddr
 , deriveMSAddrs
 
-  -- ** Custom path derivations
-, DerivPathI((:|), (:/), Deriv, DerivPrv, DerivPub)
+  -- ** Derivation paths
+, DerivPathI((:|), (:/), Deriv)
 , DerivPath
 , HardPath
 , SoftPath
+, derivePath
+, derivePubPath
+, toHard
+, toSoft
+, toGeneric
+, (++/)
 , pathToStr
+
+  -- ** Derivation path parsing
+, XKey(..)
+, ParsedPath(..)
 , parsePath
 , parseHard
 , parseSoft
-, toHard
-, toSoft
-, toMixed
-, (++/), (++|)
-, derivePath
-, derivePubPath
-, derivePathE
+, applyPath
 
   -- * Custom path address derivations
 , derivePathAddr
diff --git a/Network/Haskoin/Crypto/Base58.hs b/Network/Haskoin/Crypto/Base58.hs
--- a/Network/Haskoin/Crypto/Base58.hs
+++ b/Network/Haskoin/Crypto/Base58.hs
@@ -8,32 +8,26 @@
 , decodeBase58Check
 ) where
 
-import Control.DeepSeq (NFData, rnf)
-import Control.Monad (guard, mzero)
-
-import Data.Maybe (fromMaybe, isJust, listToMaybe)
-import Numeric (showIntAtBase, readInt)
-import Data.Aeson
-    ( Value (String)
-    , FromJSON
-    , ToJSON
-    , parseJSON
-    , toJSON
-    , withText
-    )
-
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Char8 as C
-import Data.String (IsString, fromString)
-import Data.String.Conversions (cs)
-
-import Text.Read (readPrec, parens, lexP, pfail)
-import qualified Text.Read as Read (Lexeme(Ident, String))
-
-import Network.Haskoin.Crypto.Hash
-import Network.Haskoin.Constants
-import Network.Haskoin.Util
+import           Control.DeepSeq             (NFData, rnf)
+import           Control.Monad               (guard, mzero)
+import           Data.Aeson                  (FromJSON, ToJSON, Value (String),
+                                              parseJSON, toJSON, withText)
+import           Data.Binary                 (Binary, get, put)
+import           Data.Binary.Get             (getByteString, getWord8)
+import           Data.Binary.Put             (putByteString, putWord8)
+import           Data.ByteString             (ByteString)
+import qualified Data.ByteString             as BS
+import qualified Data.ByteString.Char8       as C
+import           Data.Maybe                  (fromJust, fromMaybe, isJust,
+                                              listToMaybe)
+import           Data.String                 (IsString, fromString)
+import           Data.String.Conversions     (cs)
+import           Network.Haskoin.Constants
+import           Network.Haskoin.Crypto.Hash
+import           Network.Haskoin.Util
+import           Numeric                     (readInt, showIntAtBase)
+import           Text.Read                   (lexP, parens, pfail, readPrec)
+import qualified Text.Read                   as Read (Lexeme (Ident, String))
 
 b58Data :: ByteString
 b58Data = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
@@ -102,6 +96,23 @@
     | ScriptAddress { getAddrHash :: !Hash160 }
        deriving (Eq, Ord)
 
+instance Binary Address where
+    get = do
+        pfx <- getWord8
+        bs <- getByteString 20
+        let addr = fromJust (bsToHash160 bs)
+        f pfx addr
+      where
+        f x a | x == addrPrefix   = return (PubKeyAddress a)
+              | x == scriptPrefix = return (ScriptAddress a)
+              | otherwise = fail "Does not recognize address prefix"
+    put (PubKeyAddress h) = do
+        putWord8 addrPrefix
+        putByteString (getHash160 h)
+    put (ScriptAddress h) = do
+        putWord8 scriptPrefix
+        putByteString (getHash160 h)
+
 -- TODO: Test
 instance Show Address where
     showsPrec d a = showParen (d > 10) $
@@ -134,18 +145,11 @@
 
 -- | Transforms an Address into a base58 encoded String
 addrToBase58 :: Address -> ByteString
-addrToBase58 addr = encodeBase58Check $ case addr of
-    PubKeyAddress h -> BS.cons addrPrefix   $ getHash160 h
-    ScriptAddress h -> BS.cons scriptPrefix $ getHash160 h
+addrToBase58 = encodeBase58Check . encode'
 
 -- | Decodes an Address from a base58 encoded String. This function can fail
 -- if the String is not properly encoded as base58 or the checksum fails.
 base58ToAddr :: ByteString -> Maybe Address
 base58ToAddr str = do
     val <- decodeBase58Check str
-    guard $ BS.length val == 21
-    let f | BS.head val == addrPrefix   = Just PubKeyAddress
-          | BS.head val == scriptPrefix = Just ScriptAddress
-          | otherwise = Nothing
-    f <*> bsToHash160 (BS.tail val)
-
+    decodeToMaybe val
diff --git a/Network/Haskoin/Crypto/ExtendedKeys.hs b/Network/Haskoin/Crypto/ExtendedKeys.hs
--- a/Network/Haskoin/Crypto/ExtendedKeys.hs
+++ b/Network/Haskoin/Crypto/ExtendedKeys.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE GADTs #-}
 module Network.Haskoin.Crypto.ExtendedKeys
 ( XPubKey(..)
 , XPrvKey(..)
@@ -33,28 +32,35 @@
 , deriveMSAddr
 , deriveMSAddrs
 , cycleIndex
-  -- Custom derivations
+  -- Derivation paths
 , DerivPathI(..)
-, HardOrMixed
-, MixedOrSoft
+, HardOrGeneric
+, GenericOrSoft
 , DerivPath
 , HardPath
 , SoftPath
+, Bip32PathIndex (..)
+, derivePath
+, derivePubPath
+, toHard
+, toSoft
+, toGeneric
+, (++/)
 , pathToStr
+
+  -- Derivation path parsing
+, XKey(..)
+, ParsedPath(..)
 , parsePath
 , parseHard
 , parseSoft
-, toHard
-, toSoft
-, toMixed
-, (++/), (++|)
-, derivePath
-, derivePubPath
-, derivePathE
+, applyPath
+
 , derivePathAddr
 , derivePathAddrs
 , derivePathMSAddr
 , derivePathMSAddrs
+, concatBip32Segments
 ) where
 
 import Control.DeepSeq (NFData, rnf)
@@ -86,6 +92,7 @@
 import Network.Haskoin.Crypto.Keys
 import Network.Haskoin.Crypto.Hash
 import Network.Haskoin.Crypto.Base58
+import Data.List (foldl')
 
 {- See BIP32 for details: https://en.bitcoin.it/wiki/BIP_0032 -}
 
@@ -110,6 +117,9 @@
     , xPrvKey    :: !PrvKeyC   -- ^ The private key of this extended key node.
     } deriving (Eq)
 
+instance Ord XPrvKey where
+    compare k1 k2 = xPrvExport k1 `compare` xPrvExport k2
+
 -- TODO: Test
 instance Show XPrvKey where
     showsPrec d k = showParen (d > 10) $
@@ -148,6 +158,9 @@
     , xPubKey    :: !PubKeyC   -- ^ The public key of this extended key node.
     } deriving (Eq)
 
+instance Ord XPubKey where
+    compare k1 k2 = xPubExport k1 `compare` xPubExport k2
+
 -- TODO: Test
 instance Show XPubKey where
     showsPrec d k = showParen (d > 10) $
@@ -238,8 +251,8 @@
 -- parent private key. Given a parent key /m/ and a derivation index /i/, this
 -- function will compute m\/i'\/.
 hardSubKey :: XPrvKey  -- ^ Extended Parent private key
-            -> KeyIndex -- ^ Child derivation index
-            -> XPrvKey  -- ^ Extended child private key
+           -> KeyIndex -- ^ Child derivation index
+           -> XPrvKey  -- ^ Extended child private key
 hardSubKey xkey child
     | child >= 0 && child < 0x80000000 =
         XPrvKey (xPrvDepth xkey + 1) (xPrvFP xkey) i c k
@@ -414,45 +427,52 @@
     | i < 0x80000000 = cycle $ [i..0x7fffffff] ++ [0..(i-1)]
     | otherwise      = error $ "cycleIndex: invalid index " ++ (show i)
 
-{- Custom derivations -}
+{- Derivation Paths -}
 
 data Hard
-data Mixed
+data Generic
 data Soft
 
 type HardPath = DerivPathI Hard
-type DerivPath = DerivPathI Mixed
+type DerivPath = DerivPathI Generic
 type SoftPath = DerivPathI Soft
 
-class HardOrMixed a
-instance HardOrMixed Hard
-instance HardOrMixed Mixed
+class HardOrGeneric a
+instance HardOrGeneric Hard
+instance HardOrGeneric Generic
 
-class MixedOrSoft a
-instance MixedOrSoft Mixed
-instance MixedOrSoft Soft
+class GenericOrSoft a
+instance GenericOrSoft Generic
+instance GenericOrSoft Soft
 
+-- | Data type representing a derivation path. Two constructors are provided
+-- for specifying soft or hard derivations. The path /0/1'/2 for example can be
+-- expressed as Deriv :/ 0 :| 1 :/ 2. The HardOrGeneric and GenericOrSoft type
+-- classes are used to constrain the valid values for the phantom type t. If
+-- you mix hard (:|) and soft (:/) paths, the only valid type for t is Generic.
+-- Otherwise, t can be Hard if you only have hard derivation or Soft if you
+-- only have soft derivations.
+--
+-- Using this type is as easy as writing the required derivation like in these
+-- example:
+-- Deriv :/ 0 :/ 1 :/ 2 :: SoftPath
+-- Deriv :| 0 :| 1 :| 2 :: HardPath
+-- Deriv :| 0 :/ 1 :/ 2 :: DerivPath
 data DerivPathI t where
-    (:|) :: HardOrMixed t => !HardPath -> !KeyIndex -> DerivPathI t
-    (:/) :: MixedOrSoft t => !(DerivPathI t) -> !KeyIndex -> DerivPathI t
+    (:|)  :: HardOrGeneric t => !(DerivPathI t) -> !KeyIndex -> DerivPathI t
+    (:/)  :: GenericOrSoft t => !(DerivPathI t) -> !KeyIndex -> DerivPathI t
     Deriv :: DerivPathI t
-    DerivPrv :: DerivPathI t
-    DerivPub :: DerivPathI t
 
 instance NFData (DerivPathI t) where
     rnf p = case p of
         next :| i -> rnf i `seq` rnf next
         next :/ i -> rnf i `seq` rnf next
         Deriv     -> ()
-        DerivPrv  -> ()
-        DerivPub  -> ()
 
 instance Eq (DerivPathI t) where
     (nextA :| iA) == (nextB :| iB) = iA == iB && nextA == nextB
     (nextA :/ iA) == (nextB :/ iB) = iA == iB && nextA == nextB
     Deriv         == Deriv         = True
-    DerivPrv      == DerivPrv      = True
-    DerivPub      == DerivPub      = True
     _             == _             = False
 
 -- TODO: Test
@@ -462,9 +482,55 @@
         next :| i -> concat [ pathToStr next, "/", show i, "'" ]
         next :/ i -> concat [ pathToStr next, "/", show i ]
         Deriv     -> ""
-        DerivPrv  -> "m"
-        DerivPub  -> "M"
 
+toHard :: DerivPathI t -> Maybe HardPath
+toHard p = case p of
+    next :| i -> (:| i) <$> toHard next
+    Deriv     -> Just Deriv
+    _         -> Nothing
+
+toSoft :: DerivPathI t -> Maybe SoftPath
+toSoft p = case p of
+    next :/ i -> (:/ i) <$> toSoft next
+    Deriv     -> Just Deriv
+    _         -> Nothing
+
+toGeneric :: DerivPathI t -> DerivPath
+toGeneric p = case p of
+    next :/ i -> (toGeneric next) :/ i
+    next :| i -> (toGeneric next) :| i
+    Deriv     -> Deriv
+
+-- | Append two derivation paths together. The result will be a mixed
+-- derivation path.
+(++/) :: DerivPathI t1 -> DerivPathI t2 -> DerivPath
+(++/) p1 p2 =
+    go id (toGeneric p2) $ toGeneric p1
+  where
+    go f p = case p of
+        next :/ i -> go (f . (:/ i)) $ toGeneric next
+        next :| i -> go (f . (:| i)) $ toGeneric next
+        _ -> f
+
+-- | Derive a private key from a derivation path
+derivePath :: DerivPathI t -> XPrvKey -> XPrvKey
+derivePath = go id
+  where
+    -- Build the full derivation function starting from the end
+    go f p = case p of
+        next :| i -> go (f . flip hardSubKey i) next
+        next :/ i -> go (f . flip prvSubKey i) next
+        _ -> f
+
+-- | Derive a public key from a soft derivation path
+derivePubPath :: SoftPath -> XPubKey -> XPubKey
+derivePubPath = go id
+  where
+    -- Build the full derivation function starting from the end
+    go f p = case p of
+        next :/ i -> go (f . flip pubSubKey i) next
+        _ -> f
+
 -- TODO: Test
 instance Show DerivPath where
     showsPrec d p = showParen (d > 10) $
@@ -485,7 +551,7 @@
     readPrec = parens $ do
         Read.Ident "DerivPath" <- lexP
         Read.String str <- lexP
-        maybe pfail return $ parsePath str
+        maybe pfail (return . getParsedPath) $ parsePath str
 
 -- TODO: Test
 instance Read HardPath where
@@ -502,13 +568,20 @@
         maybe pfail return $ parseSoft str
 
 -- TODO: Test
-instance IsString DerivPath where
+instance IsString ParsedPath where
     fromString =
         fromMaybe e . parsePath
       where
         e = error "Could not parse derivation path"
 
 -- TODO: Test
+instance IsString DerivPath where
+    fromString =
+        getParsedPath . fromMaybe e . parsePath
+      where
+        e = error "Could not parse derivation path"
+
+-- TODO: Test
 instance IsString HardPath where
     fromString =
         fromMaybe e . parseHard
@@ -522,9 +595,14 @@
       where
         e = error "Could not parse soft derivation path"
 
+instance FromJSON ParsedPath where
+    parseJSON = withText "ParsedPathPath" $ \str -> case parsePath $ cs str of
+        Just p -> return p
+        _      -> mzero
+
 instance FromJSON DerivPath where
     parseJSON = withText "DerivPath" $ \str -> case parsePath $ cs str of
-        Just p -> return p
+        Just p -> return $ getParsedPath p
         _      -> mzero
 
 instance FromJSON HardPath where
@@ -540,131 +618,94 @@
 instance ToJSON (DerivPathI t) where
     toJSON = String . cs . pathToStr
 
+instance ToJSON ParsedPath where
+    toJSON (ParsedPrv p)   = String . cs . ("m" ++) . pathToStr $ p
+    toJSON (ParsedPub p)   = String . cs . ("M" ++) . pathToStr $ p
+    toJSON (ParsedEmpty p) = String . cs . ("" ++) . pathToStr $ p
+
+{- Parsing derivation paths of the form m/1/2'/3 or M/1/2'/3 -}
+
+data ParsedPath = ParsedPrv   { getParsedPath :: !DerivPath }
+                | ParsedPub   { getParsedPath :: !DerivPath }
+                | ParsedEmpty { getParsedPath :: !DerivPath }
+  deriving (Read, Show, Eq)
 -- | Parse derivation path string for extended key.
 -- Forms: “m/0'/2”, “M/2/3/4”.
-parsePath :: String -> Maybe DerivPath
+parsePath :: String -> Maybe ParsedPath
 parsePath str = do
-    ds <- reverse <$> mapM f xs
-    let (s,h) = break fst ds
-    -- No soft derivations in the hard branch
-    guard $ null $ filter (not . fst) h
-    hPath <- pHard $ map snd h
-    pSoft hPath $ map snd s
-  where
-    (x:xs) = splitOn "/" str
-    f deriv = case reads deriv of
-        [(i, "" )] -> (,) False <$> g i
-        [(i, "'")] -> (,) True <$> g i
-        _ -> Nothing
-    g i = guard (i >=0 && i < 0x80000000) >> return i
-    pSoft h (i:is) = (:/ i) <$> pSoft h is
-    pSoft h [] = return h
-    pHard :: HardOrMixed t => [KeyIndex] -> Maybe (DerivPathI t)
-    pHard (i:is) = (:| i) <$> pHard is
-    pHard [] = pEnd
-    pEnd :: Maybe (DerivPathI t)
-    pEnd = case x of
-        ""  -> Just Deriv
-        "m" -> Just DerivPrv
-        "M" -> Just DerivPub
+    res <- concatBip32Segments <$> mapM parseBip32PathIndex xs
+    case x of
+        "m" -> Just $ ParsedPrv res
+        "M" -> Just $ ParsedPub res
+        ""  -> Just $ ParsedEmpty res
         _   -> Nothing
+  where
+    (x : xs) = splitOn "/" str
 
-parseHard :: String -> Maybe HardPath
-parseHard = toHard <=< parsePath
+concatBip32Segments :: [Bip32PathIndex] -> DerivPath
+concatBip32Segments xs = foldl' appendBip32Segment Deriv xs
 
-parseSoft :: String -> Maybe SoftPath
-parseSoft = toSoft <=< parsePath
 
-toHard :: DerivPathI t -> Maybe HardPath
-toHard p = case p of
-    _ :/ _    -> Nothing
-    next :| i -> Just $ next :| i
-    Deriv     -> Just Deriv
-    DerivPrv  -> Just DerivPrv
-    DerivPub  -> Just DerivPub
+appendBip32Segment :: DerivPath -> Bip32PathIndex  -> DerivPath
+appendBip32Segment d (Bip32SoftIndex i) = d :/ i 
+appendBip32Segment d (Bip32HardIndex i) = d :| i 
 
-toSoft :: DerivPathI t -> Maybe SoftPath
-toSoft p = case p of
-    _ :| _    -> Nothing
-    next :/ i -> (:/ i) <$> toSoft next
-    Deriv     -> Just Deriv
-    DerivPrv  -> Just DerivPrv
-    DerivPub  -> Just DerivPub
 
-toMixed :: DerivPathI t -> DerivPath
-toMixed p = case p of
-    next :/ i -> (toMixed next) :/ i
-    next :| i -> next :| i
-    Deriv     -> Deriv
-    DerivPrv  -> DerivPrv
-    DerivPub  -> DerivPub
+parseBip32PathIndex :: String -> Maybe Bip32PathIndex
+parseBip32PathIndex segment = case reads segment of
+    [(i, "" )] -> guard (is31Bit i) >> ( return $ Bip32SoftIndex i )
+    [(i, "'")] -> guard (is31Bit i) >> ( return $ Bip32HardIndex i )
+    _ -> Nothing
 
--- | Append a SoftPath to any derivation path. It is always type-safe to
--- append a SoftPath to any derivation path. The result will be a mixed
--- derivation path.
-(++/) :: DerivPathI t -> SoftPath -> DerivPath
-(++/) p1 p2 =
-    go id p2 $ toMixed p1
-  where
-    go f p = case p of
-        next :/ i -> go (f . (:/ i)) next
-        _ -> f
 
--- | Append any type of derivation to a HardPath. It is always type-safe to
--- append any type of path to a HardPath. The result will be a mixed derivation
--- path.
-(++|) :: HardPath -> DerivPathI t -> DerivPath
-(++|) p1 p2 =
-    go id (toMixed p2) $ toMixed p1
-  where
-    go :: (DerivPath -> DerivPath) -> DerivPath -> (DerivPath -> DerivPath)
-    go f p = case p of
-        next :/ i -> go (f . (:/ i)) next
-        next :| i -> go (f . (:| i) . fromMaybe err . toHard) $ toMixed next
-        _ -> f
-    err = error "Error while appending paths"
+data Bip32PathIndex = Bip32HardIndex KeyIndex | Bip32SoftIndex KeyIndex
+  deriving (Read,Show,Eq)
 
--- | Derive a private key from a derivation path
-derivePath :: DerivPathI t -> XPrvKey -> XPrvKey
-derivePath path key =
-    go id path $ key
-  where
-    -- Build the full derivation function starting from the end
-    go :: (XPrvKey -> XPrvKey) -> DerivPathI t -> (XPrvKey -> XPrvKey)
-    go f p = case p of
-        next :| i -> go (f . flip hardSubKey i) next
-        next :/ i -> go (f . flip prvSubKey i) next
-        _         -> f
+is31Bit :: (Integral a) => a -> Bool
+is31Bit i = (i >=0 && i < 0x80000000) 
 
--- | Derive a public key from a soft derivation path
-derivePubPath :: SoftPath -> XPubKey -> XPubKey
-derivePubPath path key =
-    go id path $ key
-  where
-    -- Build the full derivation function starting from the end
-    go f p = case p of
-        next :/ i -> go (f . flip pubSubKey i) next
-        _         -> f
 
--- | Derive a key from a derivation path and return either a private or public
--- key depending on the initial derivation constructor. If you parsed a string
--- as m/ you will get a private key and if you parsed a string as M/ you will
--- get a public key. If you used the neutral derivation constructor `Deriv`, a
--- private key will be returned.
-derivePathE :: DerivPathI t -> XPrvKey -> Either XPubKey XPrvKey
-derivePathE path key =
-    go id path $ key
+-- Helper function to parse a hard path
+parseHard :: String -> Maybe HardPath
+parseHard = toHard . getParsedPath <=< parsePath
+
+-- Helper function to parse a soft path
+parseSoft :: String -> Maybe SoftPath
+parseSoft = toSoft . getParsedPath <=< parsePath
+
+data XKey = XPrv { getXPrvKey :: !XPrvKey }
+          | XPub { getXPubKey :: !XPubKey }
+    deriving (Eq, Show)
+
+-- | Apply a parsed path to an extended key to derive the new key defined in the
+-- path. If the path starts with m/, a private key will be returned and if the
+-- path starts with M/, a public key will be returned.
+-- Private derivations on a public key, and public derivations with a hard segment,
+-- return an error value.
+applyPath :: ParsedPath -> XKey -> Either String XKey
+applyPath path key = case (path, key) of
+    (ParsedPrv _, XPrv k) -> return $ XPrv $ derivPrvF k
+    (ParsedPrv _, XPub _) -> Left "applyPath: Invalid public key"
+    (ParsedPub _, XPrv k) -> return $ XPub $ deriveXPubKey $ derivPrvF k
+    (ParsedPub _, XPub k) -> derivPubFE >>= \f -> return $ XPub $ f k
+    -- For empty parsed paths, we take a hint from the provided key
+    (ParsedEmpty _, XPrv k) -> return $ XPrv $ derivPrvF k
+    (ParsedEmpty _, XPub k) -> derivPubFE >>= \f -> return $ XPub $ f k
   where
-    -- Build the full derivation function starting from the end
-    go :: (XPrvKey -> XPrvKey)
-       -> DerivPathI t
-       -> (XPrvKey -> Either XPubKey XPrvKey)
-    go f p = case p of
-        next :| i -> go (f . flip hardSubKey i) next
-        next :/ i -> go (f . flip prvSubKey i) next
-        -- Derive a public key as the last function
-        DerivPub  -> Left . deriveXPubKey . f
-        _         -> Right . f
+    derivPrvF  = goPrv id $ getParsedPath path
+    derivPubFE = goPubE id $ getParsedPath path
+    -- Build the full private derivation function starting from the end
+    goPrv f p = case p of
+        next :| i -> goPrv (f . flip hardSubKey i) next
+        next :/ i -> goPrv (f . flip prvSubKey i) next
+        Deriv     -> f
+    -- Build the full public derivation function starting from the end
+    goPubE f p = case p of
+        next :/ i -> goPubE (f . flip pubSubKey i) next
+        Deriv     -> Right f
+        _         -> Left "applyPath: Invalid hard derivation"
+
+{- Helpers for derivation paths and addresses -}
 
 -- | Derive an address from a given parent path.
 derivePathAddr :: XPubKey -> SoftPath -> KeyIndex -> (Address, PubKeyC)
diff --git a/Network/Haskoin/Node/Bloom.hs b/Network/Haskoin/Node/Bloom.hs
--- a/Network/Haskoin/Node/Bloom.hs
+++ b/Network/Haskoin/Node/Bloom.hs
@@ -152,8 +152,8 @@
              -- of geat consequence.
             -> BloomFlags   -- ^ Bloom filter flags
             -> BloomFilter  -- ^ Bloom filter
-bloomCreate numElem fpRate tweak flags =
-    BloomFilter (S.replicate bloomSize 0) numHashF tweak flags
+bloomCreate numElem fpRate =
+    BloomFilter (S.replicate bloomSize 0) numHashF
   where
     -- Bloom filter size in bytes
     bloomSize = truncate $ (min a b) / 8
@@ -195,7 +195,7 @@
 bloomContains bfilter bs
     | isBloomFull bfilter  = True
     | isBloomEmpty bfilter = False
-    | otherwise            = and $ map isSet idxs
+    | otherwise            = all isSet idxs
   where
     s       = bloomData bfilter
     idxs    = map (\i -> bloomHash bfilter i bs) [0..bloomHashFuncs bfilter - 1]
diff --git a/Network/Haskoin/Script/Parser.hs b/Network/Haskoin/Script/Parser.hs
--- a/Network/Haskoin/Script/Parser.hs
+++ b/Network/Haskoin/Script/Parser.hs
@@ -28,7 +28,7 @@
 ) where
 
 import Control.DeepSeq (NFData, rnf)
-import Control.Monad (liftM2, guard)
+import Control.Monad (liftM2, guard, (<=<))
 import Control.Applicative ((<|>))
 
 import Data.List (sortBy)
@@ -171,7 +171,7 @@
 
 -- | Similar to 'decodeOutput' but decodes from a ByteString
 decodeOutputBS :: ByteString -> Either String ScriptOutput
-decodeOutputBS = (decodeOutput =<<) . decodeToEither
+decodeOutputBS = decodeOutput <=< decodeToEither
 
 -- Match [ OP_N, PubKey1, ..., PubKeyM, OP_M, OP_CHECKMULTISIG ]
 matchPayMulSig :: Script -> Either String ScriptOutput
@@ -330,5 +330,5 @@
 
 -- | Similar to 'decodeInput' but decodes from a ByteString
 decodeInputBS :: ByteString -> Either String ScriptInput
-decodeInputBS = (decodeInput =<<) . decodeToEither
+decodeInputBS = decodeInput <=< decodeToEither
 
diff --git a/Network/Haskoin/Script/Types.hs b/Network/Haskoin/Script/Types.hs
--- a/Network/Haskoin/Script/Types.hs
+++ b/Network/Haskoin/Script/Types.hs
@@ -7,7 +7,7 @@
 ) where
 
 import Control.DeepSeq (NFData, rnf)
-import Control.Monad (liftM2, unless, forM_)
+import Control.Monad (unless, forM_)
 
 import Data.Word (Word8)
 import Data.Binary (Binary, get, put)
@@ -53,7 +53,7 @@
             empty <- isEmpty
             if empty
                 then return []
-                else liftM2 (:) get getScriptOps
+                else (:) <$> get <*> getScriptOps
 
     put (Script ops) = forM_ ops put
 
diff --git a/Network/Haskoin/Test.hs b/Network/Haskoin/Test.hs
--- a/Network/Haskoin/Test.hs
+++ b/Network/Haskoin/Test.hs
@@ -28,6 +28,7 @@
 , ArbitraryHardPath(..)
 , ArbitrarySoftPath(..)
 , ArbitraryDerivPath(..)
+, ArbitraryParsedPath(..)
 
   -- * Node Arbitrary instances
 , ArbitraryVarInt(..)
diff --git a/Network/Haskoin/Test/Crypto.hs b/Network/Haskoin/Test/Crypto.hs
--- a/Network/Haskoin/Test/Crypto.hs
+++ b/Network/Haskoin/Test/Crypto.hs
@@ -23,13 +23,14 @@
 , ArbitraryHardPath(..)
 , ArbitrarySoftPath(..)
 , ArbitraryDerivPath(..)
+, ArbitraryParsedPath(..)
+
 ) where
 
 import Test.QuickCheck
     ( Arbitrary
     , Gen
     , arbitrary
-    , elements
     , oneof
     , vectorOf
     , listOf
@@ -48,6 +49,7 @@
 import Network.Haskoin.Crypto.Keys
 import Network.Haskoin.Crypto.Base58
 import Network.Haskoin.Crypto.ExtendedKeys
+import Data.List (foldl')
 
 newtype ArbitraryHash160 = ArbitraryHash160 Hash160
     deriving (Eq, Show, Read)
@@ -212,38 +214,45 @@
 genIndex :: Gen Word32
 genIndex = (`clearBit` 31) <$> arbitrary
 
+data ArbitraryBip32PathIndex = ArbitraryBip32PathIndex Bip32PathIndex
+    deriving (Show,Eq)
+
+instance Arbitrary ArbitraryBip32PathIndex where
+    arbitrary = 
+        ArbitraryBip32PathIndex <$> oneof [soft, hard]
+        where soft = Bip32SoftIndex <$> genIndex
+              hard = Bip32HardIndex <$> genIndex
+
 data ArbitraryHardPath = ArbitraryHardPath HardPath
     deriving (Show, Eq)
 
 instance Arbitrary ArbitraryHardPath where
     arbitrary =
-        ArbitraryHardPath <$> (go =<< listOf genIndex)
-      where
-        go []     = elements [ Deriv, DerivPrv, DerivPub ]
-        go (i:is) = (:| i) <$> go is
+        ArbitraryHardPath . foldl' (:|) Deriv <$> listOf genIndex
 
+
 data ArbitrarySoftPath = ArbitrarySoftPath SoftPath
     deriving (Show, Eq)
 
 instance Arbitrary ArbitrarySoftPath where
     arbitrary =
-        ArbitrarySoftPath <$> (go =<< listOf genIndex)
-      where
-        go []     = elements [ Deriv, DerivPrv, DerivPub ]
-        go (i:is) = (:/ i) <$> go is
+        ArbitrarySoftPath . foldl' (:/) Deriv <$> listOf genIndex
 
 data ArbitraryDerivPath = ArbitraryDerivPath DerivPath
     deriving (Show, Eq)
 
-instance Arbitrary ArbitraryDerivPath where
+instance Arbitrary ArbitraryDerivPath where    
+    arbitrary = ArbitraryDerivPath . concatBip32Segments . map (\(ArbitraryBip32PathIndex i) -> i ) <$> arbitrary  
+        
+
+data ArbitraryParsedPath = ArbitraryParsedPath ParsedPath 
+  deriving (Show, Eq)
+
+instance Arbitrary ArbitraryParsedPath where
     arbitrary = do
-        xs  <- listOf genIndex
-        ys  <- listOf genIndex
-        return . ArbitraryDerivPath . goSoft ys =<< goHard xs
-      where
-        goSoft [] h     = h
-        goSoft (i:is) h = (goSoft is h) :/ i
-        goHard :: HardOrMixed t => [Word32] -> Gen (DerivPathI t)
-        goHard (i:is) = (:| i) <$> goHard is
-        goHard []     = elements [ Deriv, DerivPrv, DerivPub ]
+        ArbitraryDerivPath d <- arbitrary 
+        ArbitraryParsedPath <$> oneof [ pure $ ParsedPrv d
+                                      , pure $ ParsedPub d
+                                      , pure $ ParsedEmpty d ]
+
 
diff --git a/Network/Haskoin/Transaction/Types.hs b/Network/Haskoin/Transaction/Types.hs
--- a/Network/Haskoin/Transaction/Types.hs
+++ b/Network/Haskoin/Transaction/Types.hs
@@ -99,7 +99,7 @@
         maybe mzero return $ hexToTxHash $ cs t
 
 instance ToJSON TxHash where
-    toJSON h = String $ cs $ txHashToHex h
+    toJSON = String . cs . txHashToHex
 
 -- | Data type representing a bitcoin transaction
 data Tx =
diff --git a/Network/Haskoin/Util.hs b/Network/Haskoin/Util.hs
--- a/Network/Haskoin/Util.hs
+++ b/Network/Haskoin/Util.hs
@@ -76,7 +76,7 @@
 bsToInteger :: ByteString -> Integer
 bsToInteger = BS.foldr' f 0 . BS.reverse
   where
-    f w n = (toInteger w) .|. shiftL n 8
+    f w n = toInteger w .|. shiftL n 8
 
 -- | Encode an Integer to a bytestring as big endian
 integerToBS :: Integer -> ByteString
@@ -86,7 +86,7 @@
     | otherwise = error "integerToBS not defined for negative values"
   where
     f 0 = Nothing
-    f x = Just $ (fromInteger x :: Word8, x `shiftR` 8)
+    f x = Just (fromInteger x :: Word8, x `shiftR` 8)
 
 encodeHex :: ByteString -> ByteString
 encodeHex = B16.encode
@@ -110,7 +110,7 @@
 
 -- | Strict version of 'Data.Binary.runGet'
 runGet' :: Binary a => Get a -> ByteString -> a
-runGet' m = (runGet m) . BL.fromStrict
+runGet' m = runGet m . BL.fromStrict
 
 -- | Strict version of 'Data.Binary.runPut'
 runPut' :: Put -> ByteString
@@ -213,7 +213,7 @@
 -- 'Right' and 'Nothing' is mapped to 'Left'. You also pass in an error value
 -- in case 'Left' is returned.
 maybeToEither :: b -> Maybe a -> Either b a
-maybeToEither err m = maybe (Left err) Right m
+maybeToEither err = maybe (Left err) Right
 
 -- | Lift a 'Either' computation into the 'EitherT' monad
 liftEither :: Monad m => Either b a -> EitherT b m a
@@ -221,7 +221,7 @@
 
 -- | Lift a 'Maybe' computation into the 'EitherT' monad
 liftMaybe :: Monad m => b -> Maybe a -> EitherT b m a
-liftMaybe err = liftEither . (maybeToEither err)
+liftMaybe err = liftEither . maybeToEither err
 
 -- Various helpers
 
@@ -247,9 +247,9 @@
               -> [Maybe a]        -- ^ Results of the template matching
 matchTemplate [] bs _ = replicate (length bs) Nothing
 matchTemplate _  [] _ = []
-matchTemplate as (b:bs) f = case break (flip f b) as of
-    (l,(r:rs)) -> (Just r) : matchTemplate (l ++ rs) bs f
-    _          -> Nothing  : matchTemplate as bs f
+matchTemplate as (b:bs) f = case break (`f` b) as of
+    (l,r:rs) -> Just r  : matchTemplate (l ++ rs) bs f
+    _        -> Nothing : matchTemplate as bs f
 
 -- | Returns the first value of a triple.
 fst3 :: (a,b,c) -> a
@@ -270,7 +270,7 @@
 dropFieldLabel :: Int -> Options
 dropFieldLabel n = defaultOptions
     { fieldLabelModifier = map toLower . drop n
-    , omitNothingFields  = True
+    , omitNothingFields  = False -- TODO: aeson issue #293 prompted this
     }
 
 dropSumLabels :: Int -> Int -> String -> Options
diff --git a/haskoin-core.cabal b/haskoin-core.cabal
--- a/haskoin-core.cabal
+++ b/haskoin-core.cabal
@@ -1,5 +1,5 @@
 name:                  haskoin-core
-version:               0.2.0
+version:               0.3.0
 synopsis:
     Implementation of the core Bitcoin protocol features.
 description:
@@ -22,6 +22,7 @@
 
 homepage:              http://github.com/haskoin/haskoin
 bug-reports:           http://github.com/haskoin/haskoin/issues
+tested-with:           GHC==7.10.3, GHC==7.10.2, GHC==7.10.1
 stability:             stable
 license:               PublicDomain
 license-file:          UNLICENSE
@@ -30,7 +31,7 @@
 category:              Bitcoin, Finance, Network
 build-type:            Simple
 cabal-version:         >= 1.9.2
-extra-source-files:    tests/data/*.json, stack.yaml
+extra-source-files:    tests/data/*.json
 
 source-repository head
     type:     git
@@ -80,9 +81,9 @@
                 DeriveDataTypeable
                 GADTs
 
-    build-depends: aeson                    >= 0.7          && < 0.9
+    build-depends: aeson                    >= 0.7          && < 0.12
                  , base                     >= 4.8          && < 5
-                 , binary                   >= 0.7          && < 0.8
+                 , binary                   >= 0.7          && < 0.9
                  , byteable                 >= 0.1          && < 0.2
                  , bytestring               >= 0.10         && < 0.11
                  , base16-bytestring        >= 0.1          && < 0.2
@@ -98,9 +99,9 @@
                  , QuickCheck               >= 2.6          && < 2.9
                  , split                    >= 0.2          && < 0.3
                  , text                     >= 0.11         && < 1.3
-                 , time                     >= 1.4          && < 1.6
+                 , time                     >= 1.4          && < 1.7
                  , string-conversions       >= 0.4          && < 0.5
-                 , vector                   >= 0.10         && < 0.11
+                 , vector                   >= 0.10         && < 0.12
                  , secp256k1                >= 0.4          && < 0.5
                  , largeword                >= 1.2.4        && < 1.3
                  , entropy                  >= 0.3          && < 0.4
@@ -136,23 +137,27 @@
                    Network.Haskoin.Json.Tests
                    Network.Haskoin.Binary.Tests
 
-    build-depends: aeson                          >= 0.7        && < 0.9
+    build-depends: aeson                          >= 0.7        && < 0.12
                  , base                           >= 4.8        && < 5
-                 , binary                         >= 0.7        && < 0.8
+                 , binary                         >= 0.7        && < 0.9
                  , bytestring                     >= 0.10       && < 0.11
                  , containers                     >= 0.5        && < 0.6
                  , haskoin-core
                  , mtl                            >= 2.2        && < 2.3
                  , split                          >= 0.2        && < 0.3
-                 , HUnit                          >= 1.2        && < 1.3
+                 , HUnit                          >= 1.2        && < 1.4
                  , QuickCheck                     >= 2.6        && < 2.9
                  , test-framework                 >= 0.8        && < 0.9
                  , test-framework-quickcheck2     >= 0.3        && < 0.4
                  , test-framework-hunit           >= 0.3        && < 0.4
                  , text                           >= 0.11       && < 1.3
+                 , unordered-containers           >= 0.2        && < 0.3
                  , string-conversions             >= 0.4        && < 0.5
                  , largeword                      >= 1.2        && < 1.3
                  , secp256k1                      >= 0.4        && < 0.5
+                 , safe
+                 , vector
+                 , scientific
 
     ghc-options: -Wall
     hs-source-dirs: tests
diff --git a/stack.yaml b/stack.yaml
deleted file mode 100644
--- a/stack.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-flags: {}
-packages:
-- '.'
-- location:
-    git: https://github.com/haskoin/secp256k1.git
-    commit: 5ee603061b3c1eaf2943e8d2c08e6effe85f38e7
-  extra-dep: true
-extra-deps:
-- murmur3-1.0.0
-- pbkdf-1.1.1.1
-- largeword-1.2.4
-resolver: lts-3.4
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -27,7 +27,7 @@
 
 -- Transaction tests
 import qualified Network.Haskoin.Transaction.Tests (tests)
-import qualified Network.Haskoin.Transaction.Units (tests)
+import qualified Network.Haskoin.Transaction.Units (tests, satoshiCoreTxTests)
 
 -- Block tests
 import qualified Network.Haskoin.Block.Tests (tests)
@@ -40,7 +40,9 @@
 import qualified Network.Haskoin.Binary.Tests (tests)
 
 main :: IO ()
-main = defaultMain
+main = do
+  satoshiTxTests <- Network.Haskoin.Transaction.Units.satoshiCoreTxTests
+  defaultMain
     (  Network.Haskoin.Json.Tests.tests
     ++ Network.Haskoin.Binary.Tests.tests
     ++ Network.Haskoin.Util.Tests.tests
@@ -60,6 +62,7 @@
     ++ Network.Haskoin.Script.Units.tests
     ++ Network.Haskoin.Transaction.Tests.tests
     ++ Network.Haskoin.Transaction.Units.tests
+    ++ satoshiTxTests
     ++ Network.Haskoin.Block.Tests.tests
     ++ Network.Haskoin.Block.Units.tests
     )
diff --git a/tests/Network/Haskoin/Crypto/ExtendedKeys/Tests.hs b/tests/Network/Haskoin/Crypto/ExtendedKeys/Tests.hs
--- a/tests/Network/Haskoin/Crypto/ExtendedKeys/Tests.hs
+++ b/tests/Network/Haskoin/Crypto/ExtendedKeys/Tests.hs
@@ -14,7 +14,7 @@
 tests :: [Test]
 tests =
     [ testGroup "HDW Extended Keys"
-        [ testProperty "prvSubKey(k,c)*G = pubSubKey(k*G,c)" subkeyTest
+        [ testProperty "pubkey of subkey is subkey of pubkey / prvSubKey(k,c)*G = pubSubKey(k*G,c)" pubKeyOfSubKeyIsSubKeyOfPubKey
         , testProperty "fromB58 . toB58 prvKey" b58PrvKey
         , testProperty "fromB58 . toB58 pubKey" b58PubKey
         ]
@@ -34,8 +34,8 @@
 
 {- HDW Extended Keys -}
 
-subkeyTest :: ArbitraryXPrvKey -> Word32 -> Bool
-subkeyTest (ArbitraryXPrvKey k) i =
+pubKeyOfSubKeyIsSubKeyOfPubKey :: ArbitraryXPrvKey -> Word32 -> Bool
+pubKeyOfSubKeyIsSubKeyOfPubKey (ArbitraryXPrvKey k) i =
     (deriveXPubKey $ prvSubKey k i') == (pubSubKey (deriveXPubKey k) i')
   where
     i' = fromIntegral $ i .&. 0x7fffffff -- make it a public derivation
diff --git a/tests/Network/Haskoin/Crypto/ExtendedKeys/Units.hs b/tests/Network/Haskoin/Crypto/ExtendedKeys/Units.hs
--- a/tests/Network/Haskoin/Crypto/ExtendedKeys/Units.hs
+++ b/tests/Network/Haskoin/Crypto/ExtendedKeys/Units.hs
@@ -38,7 +38,8 @@
             runXKeyVec (xKeyVec2 !! 5)
         ]
     , testGroup "BIP32 subkey derivation using string path"
-        [ testGroup "Either Derivations" testDerivePathE
+        [ testGroup "Either Derivations" testApplyPath
+        , testGroup "Either Derivations" testBadApplyPath
         , testGroup "Public Derivations" testDerivePubPath
         , testGroup "Private Derivations" testDerivePrvPath
         , testGroup "Path Parsing" testParsePath
@@ -59,7 +60,7 @@
     path <- jsonPathVectors
     return $ testCase ("Path " ++ path) $
         assertEqual path (B8.pack $ "[\"" ++ path ++ "\"]")
-            (encode [fromString path :: DerivPath])
+            (encode [fromString path :: ParsedPath])
 
 jsonPathVectors :: [String]
 jsonPathVectors =
@@ -81,7 +82,7 @@
     return $ testCase ("Path " ++ path) $
         assertBool path (t $ parsePath path)
 
-parsePathVectors :: [(String, Maybe DerivPath -> Bool)]
+parsePathVectors :: [(String, Maybe ParsedPath -> Bool)]
 parsePathVectors =
     [ ("m", isJust)
     , ("m/0'", isJust)
@@ -96,20 +97,27 @@
     , ("M/1/2/3/4/5/6/7/8", isJust)
     , ("m/1'/2'/3/4", isJust)
     , ("M/1'/2'/3/4", isJust)
-    , ("m/1/2'/3/4'", isNothing)
-    , ("M/1/2'/3/4'", isNothing)
+    , ("m/1/2'/3/4'", isJust)
+    , ("M/1/2'/3/4'", isJust)
     , ("meh", isNothing)
     , ("infinity", isNothing)
     , ("NaN", isNothing)
     ]
 
-testDerivePathE :: [Test]
-testDerivePathE = do
-    (key, path, final) <- derivePathVectors
+testApplyPath :: [Test]
+testApplyPath = do
+    (key, path, final) <- applyPathVectors
     return $ testCase ("Path " ++ path) $
         assertEqual path final $
-            derivePathE (fromString path :: DerivPath) key
+            applyPath (fromJust $ parsePath path) key
 
+testBadApplyPath :: [Test]
+testBadApplyPath = do
+    (key, path) <- badApplyPathVectors
+    return $ testCase ("Path " ++ path) $
+        assertBool path $ isLeft $
+            applyPath (fromJust $ parsePath path) key
+
 testDerivePubPath :: [Test]
 testDerivePubPath = do
     (key, path, final) <- derivePubPathVectors
@@ -160,30 +168,47 @@
         "xprv9s21ZrQH143K46iDVRSyFfGfMgQjzC4BV3ZUfNbG7PHQrJjE53ofAn5gYkp6KQ\
         \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"
 
-derivePathVectors :: [(XPrvKey, String, Either XPubKey XPrvKey)]
-derivePathVectors =
-    [ ( xprv, "m", Right xprv )
-    , ( xprv, "M", Left xpub )
-    , ( xprv, "m/8'", Right $ hardSubKey xprv 8 )
-    , ( xprv, "M/8'", Left $ deriveXPubKey $ hardSubKey xprv 8 )
-    , ( xprv, "m/8'/30/1"
-      , Right $ foldl prvSubKey (hardSubKey xprv 8) [30,1]
+applyPathVectors :: [(XKey, String, Either String XKey)]
+applyPathVectors =
+    [ ( XPrv xprv, "m", Right $ XPrv xprv )
+    , ( XPrv xprv, "M", Right $ XPub xpub )
+    , ( XPrv xprv, "m/8'", Right $ XPrv $ hardSubKey xprv 8 )
+    , ( XPrv xprv, "M/8'", Right $ XPub $ deriveXPubKey $ hardSubKey xprv 8 )
+    , ( XPrv xprv, "m/8'/30/1"
+      , Right $ XPrv $ foldl prvSubKey (hardSubKey xprv 8) [30,1]
       )
-    , ( xprv, "M/8'/30/1"
-      , Left $ deriveXPubKey $ foldl prvSubKey (hardSubKey xprv 8) [30,1]
+    , ( XPrv xprv, "M/8'/30/1"
+      , Right $ XPub $
+          deriveXPubKey $ foldl prvSubKey (hardSubKey xprv 8) [30,1]
       )
-    , ( xprv, "m/3/20"
-      , Right $ foldl prvSubKey xprv [3,20]
+    , ( XPrv xprv, "m/3/20"
+      , Right $ XPrv $ foldl prvSubKey xprv [3,20]
       )
-    , ( xprv, "M/3/20"
-      , Left $ deriveXPubKey $ foldl prvSubKey xprv [3,20]
+    , ( XPrv xprv, "M/3/20"
+      , Right $ XPub $ deriveXPubKey $ foldl prvSubKey xprv [3,20]
       )
+    , ( XPub xpub, "M/3/20"
+      , Right $ XPub $ deriveXPubKey $ foldl prvSubKey xprv [3,20]
+      )
     ]
   where
     xprv = fromJust $ xPrvImport
         "xprv9s21ZrQH143K46iDVRSyFfGfMgQjzC4BV3ZUfNbG7PHQrJjE53ofAn5gYkp6KQ\
         \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"
     xpub = deriveXPubKey xprv
+
+badApplyPathVectors :: [(XKey, String)]
+badApplyPathVectors = [ 
+    ( XPub xpub, "m/8'" )
+  , ( XPub xpub, "M/8'" )
+  , ( XPub xpub, "M/1/2/3'/4/5" )
+  ]
+  where
+    xprv = fromJust $ xPrvImport
+        "xprv9s21ZrQH143K46iDVRSyFfGfMgQjzC4BV3ZUfNbG7PHQrJjE53ofAn5gYkp6KQ\
+        \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"
+    xpub = deriveXPubKey xprv
+
 
 runXKeyVec :: ([ByteString], XPrvKey) -> Assertion
 runXKeyVec (v, m) = do
diff --git a/tests/Network/Haskoin/Crypto/Mnemonic/Tests.hs b/tests/Network/Haskoin/Crypto/Mnemonic/Tests.hs
--- a/tests/Network/Haskoin/Crypto/Mnemonic/Tests.hs
+++ b/tests/Network/Haskoin/Crypto/Mnemonic/Tests.hs
@@ -89,7 +89,7 @@
     l = length . C.words . fromRight $ toMnemonic bs
 
 toMnemonicVar :: [Word32] -> Property
-toMnemonicVar ls = not (length ls > 8) ==> l == wc
+toMnemonicVar ls = length ls <= 8 ==> l == wc
   where
     bs = binWordsToBS ls
     bl = BS.length bs
diff --git a/tests/Network/Haskoin/Json/Tests.hs b/tests/Network/Haskoin/Json/Tests.hs
--- a/tests/Network/Haskoin/Json/Tests.hs
+++ b/tests/Network/Haskoin/Json/Tests.hs
@@ -4,6 +4,7 @@
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 
 import Data.Aeson (FromJSON, ToJSON, decode, encode)
+import Data.HashMap.Strict (singleton)
 
 import Network.Haskoin.Test
 
@@ -24,9 +25,11 @@
         , testProperty "XPrvKey" $ \(ArbitraryXPrvKey x) -> metaID x
         , testProperty "XPubKey" $ \(ArbitraryXPubKey _ x) -> metaID x
         , testProperty "DerivPath" $ \(ArbitraryDerivPath x) -> metaID x
+        , testProperty "ParsedPath" $ \(ArbitraryParsedPath x) -> metaID x
         ]
     ]
 
 metaID :: (FromJSON a, ToJSON a, Eq a) => a -> Bool
-metaID x = (decode . encode) [x] == Just [x]
+metaID x = (decode . encode) (singleton ("object" :: String) x) ==
+    Just (singleton ("object" :: String) x)
 
diff --git a/tests/Network/Haskoin/Transaction/Units.hs b/tests/Network/Haskoin/Transaction/Units.hs
--- a/tests/Network/Haskoin/Transaction/Units.hs
+++ b/tests/Network/Haskoin/Transaction/Units.hs
@@ -1,5 +1,5 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Network.Haskoin.Transaction.Units (tests) where
+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
+module Network.Haskoin.Transaction.Units (tests, satoshiCoreTxTests) where
 
 import Test.HUnit (Assertion, assertBool)
 import Test.Framework (Test, testGroup)
@@ -8,8 +8,18 @@
 import Data.Word (Word32, Word64)
 import Data.Maybe (fromJust)
 import Data.Binary.Get (getWord32le)
+import Data.Binary.Put (putWord32le)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as BS (reverse)
+import qualified Data.ByteString.Lazy as LBS 
+import Safe (readMay)
+import GHC.Exts( IsString(..) )
+import qualified Data.Aeson as Aeson 
+import qualified Data.Aeson.Types as Aeson.Types
+import qualified Data.Vector as V
+import Data.String.Conversions (convertString)
+import Data.List (groupBy)
+import qualified Data.Either
 
 import Network.Haskoin.Transaction
 import Network.Haskoin.Script
@@ -23,6 +33,7 @@
         ( map mapPKHashVec $ zip pkHashVec [0..] )
     , testGroup "Verify transaction (bitcoind /test/data/tx_valid.json)"
         ( map mapVerifyVec $ zip verifyVec [0..] )
+    , testCase "" tEncodeSatoshiCoreScriptPubKey
     ]
 
 mapTxIDVec :: ((ByteString, ByteString), Int) -> Test.Framework.Test
@@ -64,22 +75,28 @@
           f (tid,ix) = OutPoint (fromJust $ hexToTxHash tid) ix
 
 
-mapVerifyVec :: (([(ByteString, ByteString, ByteString)], ByteString), Int)
+mapVerifyVec :: (SatoshiCoreTxTest, Int)
              -> Test.Framework.Test
 mapVerifyVec (v, i) = testCase name $ runVerifyVec v i
-    where name = "Verify Tx " ++ (show i)
+    where name = "Verify Tx " ++ (show i) ++ ", about: " ++ (satCoreTxTestDescription $ v)
 
-runVerifyVec :: ([(ByteString, ByteString, ByteString)], ByteString) -> Int -> Assertion
-runVerifyVec (is, bsTx) i =
-    assertBool name $ verifyStdTx tx $ map f is
+runVerifyVec :: SatoshiCoreTxTest -> Int -> Assertion
+runVerifyVec (SatoshiCoreTxTest description is bsTx) i =
+    assertBool name $ verifyStdTx tx outputsAndOutpoints
   where
-    name = "    > Verify transaction " ++ (show i)
-    tx  = decode' (fromJust $ decodeHex bsTx)
-    f (o1, o2, bsScript) =
-        let s = fromRight $ decodeOutputBS $ fromJust $ decodeHex $ bsScript
+    name = "    > Verify transaction " ++ (show i) ++ "bsTx: " ++ convertString bsTx
+    tx :: Tx
+    tx  = decode' . fromJust . decodeHex $ bsTx
+    outputsAndOutpoints :: [(ScriptOutput, OutPoint)] 
+    outputsAndOutpoints = map f is
+    f (SatoshiCoreTxTestInput bsOutputHash bsOutputIndex bsOutputScriptPubKey) =
+        let s :: ScriptOutput
+            s = either (\e -> error $ "could not decode: " ++ convertString bsOutputScriptPubKey) id
+                  . decodeOutputBS . fromJust . decodeHex $ bsOutputScriptPubKey
+            op :: OutPoint
             op = OutPoint
-                (decode' $ BS.reverse $ fromJust $ decodeHex o1)
-                (runGet' getWord32le $ fromJust $ decodeHex o2)
+                (decode' . BS.reverse . fromJust . decodeHex $ bsOutputHash)
+                (runGet' getWord32le  . fromJust . decodeHex $ bsOutputIndex)
         in (s, op)
 
 -- These test vectors have been generated from bitcoind raw transaction api
@@ -113,13 +130,27 @@
       )
     ]
 
+data SatoshiCoreTxTest = 
+  SatoshiCoreTxTest { satCoreTxTestDescription :: String,
+                      satCoreTxTestInputs :: [SatoshiCoreTxTestInput], 
+                      satCoreTxTestSerTx :: ByteString}
+  deriving (Read,Show)
+
+data SatoshiCoreTxTestInput = 
+  SatoshiCoreTxTestInput { satCoreTxTestPrevoutHash :: ByteString,
+                           satCoreTxTestPrevoutIndex :: ByteString,
+                           satCoreTxTestPrevoutScriptPubKey :: ByteString}
+  deriving (Read,Show)
+
 {- Test vectors from bitcoind -}
 -- github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json
-
-verifyVec :: [([(ByteString, ByteString, ByteString)], ByteString)]
+-- [[(prevout hash, prevout index, prevout scriptPubKey)], serialized tx], 
+verifyVec :: [SatoshiCoreTxTest]
 verifyVec =
+  let toSatCoreTest (is, sertx, description) = SatoshiCoreTxTest description (map toInputs is) sertx
+      toInputs (a,b,c) = SatoshiCoreTxTestInput a b c
+  in  map toSatCoreTest
     [
-      -- It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts
       ( [
           ( "60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1"
           , "00000000"
@@ -127,8 +158,8 @@
           )
         ]
       , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"
+      , "It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"
       )
-      -- It has an arbitrary extra byte stuffed into the signature at pos length - 2
     , ( [
           ( "60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1"
           , "00000000"
@@ -136,8 +167,8 @@
           )
         ]
       , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"
+      , "It has an arbitrary extra byte stuffed into the signature at pos length - 2"
       )
-      -- it is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)
     , ( [
           ( "406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602"
           , "00000000"
@@ -145,8 +176,8 @@
           )
         ]
       , "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000"
+      , "it is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"
       )
-      -- It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation
     , ( [
           ( "b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d"
           , "00000000"
@@ -158,9 +189,9 @@
           )
         ]
       , "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000"
+      , "It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"
       )
-      -- It results in signing the constant 1, instead of something generated based on the transaction,
-      -- when the input doing the signing has an index greater than the maximum output index
+      
     , ( [
           ( "0000000000000000000000000000000000000000000000000000000000000100"
           , "00000000"
@@ -172,8 +203,9 @@
           )
         ]
         , "01000000020002000000000000000000000000000000000000000000000000000000000000000000006a47304402200469f169b8091cd18a2770136be7411f079b3ac2b5c199885eb66a80aa3ed75002201fa89f3e6f80974e1b3474e70a0fbe907c766137ff231e4dd05a555d8544536701210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000"
+        , "-- It results in signing the constant 1, instead of something generated based on the transaction,\
+          \-- when the input doing the signing has an index greater than the maximum output index"
       )
-      -- A valid P2SH Transaction using the standard transaction type put forth in BIP 16
     , ( [
           ( "0000000000000000000000000000000000000000000000000000000000000100"
           , "00000000"
@@ -181,8 +213,8 @@
           )
         ]
       , "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000"
+      , "A valid P2SH Transaction using the standard transaction type put forth in BIP 16"
       )
-      -- MAX_MONEY output
     , ( [
           ( "0000000000000000000000000000000000000000000000000000000000000100"
           , "00000000"
@@ -190,8 +222,8 @@
           )
         ]
       , "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000"
+      , "MAX_MONEY output"
       )
-      -- MAX_MONEY output + 0 output
     , ( [
           ( "0000000000000000000000000000000000000000000000000000000000000100"
           , "00000000"
@@ -199,8 +231,8 @@
           )
         ]
       , "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000"
+      , "MAX_MONEY output + 0 output"
       )
-      -- Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY
     , ( [
           ( "0000000000000000000000000000000000000000000000000000000000000100"
           , "00000000"
@@ -212,8 +244,8 @@
           )
         ]
       , "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"
+      , "Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"
       )
-      -- Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed
     , ( [
           ( "0000000000000000000000000000000000000000000000000000000000000100"
           , "00000000"
@@ -225,8 +257,8 @@
           )
         ]
       , "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000"
+      , "Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"
       )
-      -- several SIGHASH_SINGLE signatures
     , ( [
           ( "63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70"
           , "00000000"
@@ -242,6 +274,105 @@
           )
         ]
       , "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"
+      , "several SIGHASH_SINGLE signatures"
       )
     ]
+
+tEncodeSatoshiCoreScriptPubKey :: Assertion
+tEncodeSatoshiCoreScriptPubKey = assertBool "tEncodeSatoshiCoreScriptPubKey" $ 
+  t1BsOutputScriptPubKey == encodeSatoshiCoreScriptPubKey t1SatoshiCoreJsonScriptPubKey
+  where 
+    t1BsOutputScriptPubKey :: ByteString
+    t1BsOutputScriptPubKey = "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"
+    t1SatoshiCoreJsonScriptPubKey :: String
+    t1SatoshiCoreJsonScriptPubKey = "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"
+
+
+encodeSatoshiCoreScriptPubKey :: String -> ByteString
+encodeSatoshiCoreScriptPubKey = 
+  mconcat . map encodeSatoshiCoreScriptPiece . words
+  where 
+    encodeSatoshiCoreScriptPiece :: String -> ByteString
+    encodeSatoshiCoreScriptPiece s = case (readMay ("OP_" ++ s) :: Maybe ScriptOp) of
+      Just op -> encodeHex . encode' $ op
+      Nothing -> case (take 2 s) of 
+          "OP" -> encodeHex . encode' . (read :: String -> ScriptOp) $ s
+          "0x" -> ( fromString . drop 2 :: String -> ByteString) $ s          
+          _ -> case (readMay s :: Maybe Int) of -- can we get rid of this case now?
+            Just i -> encodeHex . encode' . intToScriptOp $ i
+            Nothing -> error $ "encodeSatoshiCoreScriptPubKey: " ++ s
+
+satoshiCoreTxTests :: IO [Test]
+satoshiCoreTxTests = do
+  txVec <- satoshiCoreTxVec
+  return $ [ 
+    testGroup "Verify transaction (bitcoind /test/data/tx_valid.json) (using copied source json)"
+      ( map mapVerifyVec . filter isCurrentlyPassing $ zip txVec [0..] ) 
+    ]
+  where
+    passingTests = [0..5] ++ [8] ++ [11..13] ++ [16..18] ++ [20] ++ [52]
+    isCurrentlyPassing (_, testNum) = elem testNum passingTests
+
+
+type TestComment = String
+satoshiCoreTxVec :: IO [SatoshiCoreTxTest]
+satoshiCoreTxVec = do 
+    tx_validBS <- LBS.readFile "tests/data/tx_valid.json"
+    let testsAndComments = maybe (error $ "satoshiCoreTxVec, couldn't decode json") id . Aeson.decode $ tx_validBS            
+    return $ case testsAndComments of
+        (Aeson.Array arr) -> 
+            let testsOrComments = map toTestOrComment . V.toList $ arr 
+            in  processTestsAndComments testsOrComments
+        _ -> error $ "satoshiCoreTxVec, testsAndComments not an array"
+      where
+        processTestsAndComments :: [Either TestComment SatoshiCoreTxTest] -> [SatoshiCoreTxTest]
+        processTestsAndComments testOrComments = 
+          -- ghetto parser, because this older version of ootb aeson parser isn't parsec based
+          -- to do ideally soon, upgrade aeson, use aeson/attoparsec, should be much cleaner
+          let grouper = Data.List.groupBy (\x y -> (Data.Either.isLeft x && Data.Either.isLeft y) 
+                                                || (Data.Either.isRight x && Data.Either.isRight y))              
+              takePairs (a:b:xs) = (a,b):takePairs xs
+              takePairs _ = [] -- ugh, wish we were using a real parser.
+              includeDescriptions (descriptionLines,tests') = map updateDescription tests'
+                where updateDescription (Right (SatoshiCoreTxTest _ inputs ser)) = SatoshiCoreTxTest description inputs ser
+                      updateDescription e = error $ "updateDescription: " ++ show e
+                      description = unwords . map fromLeft $ descriptionLines
+          in  concat . map includeDescriptions . takePairs . grouper $ testOrComments
+
+toTestOrComment :: Aeson.Value -> (Either TestComment SatoshiCoreTxTest)
+toTestOrComment testVectorOrComment = 
+  case testVectorOrComment of
+    (Aeson.Types.Array arr) -> 
+      case (V.length arr) of
+        1 ->  let comment = arr V.! 0
+              in case comment of
+                   Aeson.Types.String txt -> Left . convertString $ txt
+                   _ -> error $ "toTestOrComment, comment not text"
+        3 ->  let inputs = case ( arr V.! 0 ) of            
+                    (Aeson.Array inputsV) -> 
+                      let toInput ( Aeson.Array oneInputV ) = 
+                            let hash = case oneInputV V.! 0 of 
+                                  Aeson.String txt -> convertString txt
+                                  _ -> error "processItem, hash not a string"
+                                index = case oneInputV V.! 01 of 
+                                  Aeson.Number n -> encodeHex . runPut' . putWord32le . floor $ n
+                                  _ -> error "processItem, n not a number"
+                                pubkey = case oneInputV V.! 2 of
+                                  Aeson.String txt -> encodeSatoshiCoreScriptPubKey . convertString $ txt
+                                  _ -> error "processItem, pubkey not a string"
+                            in  SatoshiCoreTxTestInput hash index pubkey 
+                          toInput _ = error "processItem, oneInputV not an array"
+                      in  map toInput . V.toList $ inputsV
+                    _ -> error "inputs not an array"
+                  tx = let txVal = arr V.! 1
+                       in case txVal of
+                          Aeson.Types.String txt -> convertString txt
+                          _ -> error $ "toTestOrComment, tx, not text"
+                  -- flags -- v V.! 2  -- ignored for now? 
+              in  Right $ SatoshiCoreTxTest "" inputs tx 
+        i -> error $ "toTestOrComment, bad length: " ++ show i 
+    _ -> error "testVectorOrComment is not an array"
+
+
+
 
diff --git a/tests/data/tx_valid.json b/tests/data/tx_valid.json
new file mode 100644
--- /dev/null
+++ b/tests/data/tx_valid.json
@@ -0,0 +1,321 @@
+[
+["The following are deserialized transactions which are valid."],
+["They are in the form"],
+["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"],
+["serializedTransaction, verifyFlags]"],
+["Objects that are only a single string (like this one) are ignored"],
+
+["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
+["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"],
+["See http://r6.ca/blog/20111119T211504Z.html"],
+["It is also the first OP_CHECKMULTISIG transaction in standard form"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
+
+["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
+["It is an OP_CHECKMULTISIG with an arbitrary extra byte stuffed into the signature at pos length - 2"],
+["The dummy byte is fine however, so the NULLDUMMY flag should be happy"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"],
+
+["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"],
+["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
+
+["As above, but using a OP_1"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
+
+["As above, but using a OP_1NEGATE"],
+[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]],
+"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"],
+
+["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"],
+["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"],
+[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]],
+"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"],
+
+["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
+
+["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
+
+["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
+["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
+[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
+["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
+"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
+
+["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"],
+["It results in signing the constant 1, instead of something generated based on the transaction,"],
+["when the input doing the signing has an index greater than the maximum output index"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]],
+"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"],
+
+["An invalid P2SH Transaction"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"],
+
+["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"],
+
+["Tests for CheckTransaction()"],
+["MAX_MONEY output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"],
+
+["MAX_MONEY output + 0 output"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"],
+
+["Coinbase of size 2"],
+["Note the input is just required to make the tester happy"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"],
+
+["Coinbase of size 100"],
+["Note the input is just required to make the tester happy"],
+[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]],
+"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"],
+
+["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
+  ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
+ "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"],
+
+["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"],
+  ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]],
+ "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"],
+
+["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"],
+[[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
+ ["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"],
+ ["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]],
+ "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"],
+
+ ["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"],
+ [[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]],
+ "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"],
+
+["Correct signature order"],
+["Note the input is just required to make the tester happy"],
+[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]],
+"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"],
+
+["cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0"],
+[[["cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"]],
+"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"],
+
+["Empty pubkey"],
+[[["229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"]],
+"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"],
+
+["Empty signature"],
+[[["9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"]],
+"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"],
+
+[[["444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"]],
+"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"],
+
+[[["e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"]],
+"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"],
+
+[[["ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"]],
+"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"],
+
+[[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]],
+"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"],
+
+
+["OP_CODESEPARATOR tests"],
+
+["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"],
+[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
+"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"],
+[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]],
+"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Hashed data starts at the CODESEPARATOR"],
+[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]],
+"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"],
+
+["But only if execution has reached it"],
+[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]],
+"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"],
+
+["CODESEPARATOR in an unexecuted IF block does not change what is hashed"],
+[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
+"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "P2SH"],
+
+["As above, with the IF block executed"],
+[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
+"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "P2SH"],
+
+
+["CHECKSIG is legal in scriptSigs"],
+[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Same semantics for OP_CODESEPARATOR"],
+[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."],
+[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["That also includes ahead of the opcode being executed."],
+[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
+"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
+
+["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
+
+["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
+[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
+  ["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]],
+"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"],
+
+["Same idea, but with bare CHECKMULTISIG"],
+[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
+  ["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
+"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
+
+
+["CHECKLOCKTIMEVERIFY tests"],
+
+["By-height locks, with argument == 0 and == tx nLockTime"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Any non-maxint nSequence is fine"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["The argument can be calculated rather than created directly by a PUSHDATA"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD CHECKLOCKTIMEVERIFY 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD CHECKLOCKTIMEVERIFY 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["5 byte non-minimally-encoded arguments are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKLOCKTIMEVERIFY 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Valid CHECKLOCKTIMEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["A transaction with a non-standard DER signature."],
+[[["b1dbc81696c8a9c0fccd0693ab66d7c368dbc38c0def4e800685560ddd1b2132", 0, "DUP HASH160 0x14 0x4b3bd7eba3bc0284fd3007be7f3be275e94f5826 EQUALVERIFY CHECKSIG"]],
+"010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "P2SH"],
+
+["CHECKSEQUENCEVERIFY tests"],
+
+["By-height locks, with argument == 0 and == txin.nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "65535 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["By-time locks, with argument == 0 and == txin.nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4259839 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Upper sequence with upper sequence is fine"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument 2^31 with various nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument 2^32-1 with various nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Argument 3<<31 with various nSequence"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "6442450944 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["5 byte non-minimally-encoded operandss are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["The argument can be calculated rather than created directly by a PUSHDATA"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194303 1ADD NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4194304 1SUB NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["An ADD producing a 5-byte result that sets CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 65536 NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 4259840 ADD NOP3 1"]],
+"020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Valid CHECKSEQUENCEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Valid CHECKSEQUENCEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7c17aff532f22beb54069942f9bf567a66133eaf EQUAL"]],
+"0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "P2SH,CHECKSEQUENCEVERIFY"],
+
+["Make diffs cleaner by leaving a comment here without comma at the end"]
+]
