haskoin-core 0.17.6 → 0.18.0
raw patch · 6 files changed
+126/−18 lines, 6 files
Files
- CHANGELOG.md +4/−0
- haskoin-core.cabal +2/−2
- src/Haskoin/Address.hs +30/−14
- src/Haskoin/Script/Standard.hs +67/−1
- src/Haskoin/Util/Arbitrary/Address.hs +10/−0
- src/Haskoin/Util/Arbitrary/Script.hs +13/−1
CHANGELOG.md view
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.18.0+### Added+- Support SegWit addresses with version other than 0.+ ## 0.17.6 ### Added - Serialize instances for `XPubKey` and `XPrvKey`.
haskoin-core.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 80ca7faee9e1700b5927a262126a774fb45156219675eb255ba45e31aabcfe92+-- hash: 9861fe70166471990a6ee8fcf42174a9d40cda5b4e28119073d56a221e78fee3 name: haskoin-core-version: 0.17.6+version: 0.18.0 synopsis: Bitcoin & Bitcoin Cash library for Haskell description: Please see the README on GitHub at <https://github.com/haskoin/haskoin-core#readme> category: Bitcoin, Finance, Network
src/Haskoin/Address.hs view
@@ -64,6 +64,7 @@ import Data.Maybe import Data.Serialize as S import Data.Text (Text)+import Data.Word (Word8) import GHC.Generics (Generic) import Haskoin.Address.Base58 import Haskoin.Address.Bech32@@ -96,6 +97,11 @@ { getAddrHash256 :: !Hash256 -- ^ HASH256 hash of script }+ -- | other witness address+ | WitnessAddress+ { getAddrVersion :: !Word8+ , getAddrData :: !ByteString+ } deriving (Eq, Ord, Generic, Show, Read, Serialize, Hashable, NFData) -- | 'Address' pays to a public key hash.@@ -118,6 +124,10 @@ isWitnessScriptAddress WitnessScriptAddress {} = True isWitnessScriptAddress _ = False +isWitnessAddress :: Address -> Bool+isWitnessAddress WitnessAddress {} = True+isWitnessAddress _ = False+ addrToJSON :: Network -> Address -> Value addrToJSON net a = toJSON (addrToText net a) @@ -151,6 +161,9 @@ addrToText net WitnessScriptAddress {getAddrHash256 = h} = do hrp <- getBech32Prefix net segwitEncode hrp 0 (B.unpack (S.encode h))+addrToText net WitnessAddress {getAddrVersion = v, getAddrData = d} = do+ hrp <- getBech32Prefix net+ segwitEncode hrp v (B.unpack d) -- | Parse 'Base58', 'Bech32' or 'CashAddr' address, depending on network. textToAddr :: Network -> Text -> Maybe Address@@ -169,11 +182,12 @@ bech32ToAddr net txt = do hrp <- getBech32Prefix net (ver, bs) <- second B.pack <$> segwitDecode hrp txt- guard (ver == 0) -- We only support version 0 for now- case B.length bs of- 20 -> WitnessPubKeyAddress <$> eitherToMaybe (S.decode bs)- 32 -> WitnessScriptAddress <$> eitherToMaybe (S.decode bs)- _ -> Nothing+ case ver of+ 0 -> case B.length bs of+ 20 -> WitnessPubKeyAddress <$> eitherToMaybe (S.decode bs)+ 32 -> WitnessScriptAddress <$> eitherToMaybe (S.decode bs)+ _ -> Nothing+ _ -> Just $ WitnessAddress ver bs base58ToAddr :: Network -> Text -> Maybe Address base58ToAddr net txt =@@ -250,10 +264,11 @@ addressToOutput :: Address -> ScriptOutput addressToOutput = \case- (PubKeyAddress h) -> PayPKHash h- (ScriptAddress h) -> PayScriptHash h- (WitnessPubKeyAddress h) -> PayWitnessPKHash h- (WitnessScriptAddress h) -> PayWitnessScriptHash h+ PubKeyAddress h -> PayPKHash h+ ScriptAddress h -> PayScriptHash h+ WitnessPubKeyAddress h -> PayWitnessPKHash h+ WitnessScriptAddress h -> PayWitnessScriptHash h+ WitnessAddress v d -> PayWitness v d -- | Get output script AST for an 'Address'. addressToScript :: Address -> Script@@ -277,11 +292,12 @@ outputAddress :: ScriptOutput -> Maybe Address outputAddress = \case- (PayPKHash h) -> Just $ PubKeyAddress h- (PayScriptHash h) -> Just $ ScriptAddress h- (PayPK k) -> Just $ pubKeyAddr k- (PayWitnessPKHash h) -> Just $ WitnessPubKeyAddress h- (PayWitnessScriptHash h) -> Just $ WitnessScriptAddress h+ PayPKHash h -> Just $ PubKeyAddress h+ PayScriptHash h -> Just $ ScriptAddress h+ PayPK k -> Just $ pubKeyAddr k+ PayWitnessPKHash h -> Just $ WitnessPubKeyAddress h+ PayWitnessScriptHash h -> Just $ WitnessScriptAddress h+ PayWitness v d -> Just $ WitnessAddress v d _ -> Nothing -- | Infer the 'Address' of a 'ScriptInput'.
src/Haskoin/Script/Standard.hs view
@@ -53,7 +53,9 @@ import Data.Function (on) import Data.Hashable import Data.List (sortBy)+import Data.Maybe (fromJust, isJust) import Data.Serialize as S+import Data.Word (Word8) import GHC.Generics (Generic) import Haskoin.Constants import Haskoin.Crypto@@ -79,6 +81,10 @@ | PayWitnessPKHash { getOutputHash :: !Hash160 } -- | pay to witness script hash | PayWitnessScriptHash { getScriptHash :: !Hash256 }+ -- | another pay to witness address+ | PayWitness { getWitnessVersion :: !Word8+ , getWitnessData :: !ByteString+ } -- | provably unspendable data carrier | DataCarrier { getOutputData :: !ByteString } deriving (Eq, Show, Read, Generic, Hashable, NFData)@@ -124,6 +130,11 @@ isPayWitnessScriptHash (PayWitnessScriptHash _) = True isPayWitnessScriptHash _ = False +-- | Is script paying to a different type of witness address?+isPayWitness :: ScriptOutput -> Bool+isPayWitness (PayWitness _ _) = True+isPayWitness _ = False+ -- | Is script a data carrier output? isDataCarrier :: ScriptOutput -> Bool isDataCarrier (DataCarrier _) = True@@ -145,11 +156,57 @@ [OP_0, OP_PUSHDATA bs OPCODE] | BS.length bs == 20 -> PayWitnessPKHash <$> S.decode bs | BS.length bs == 32 -> PayWitnessScriptHash <$> S.decode bs+ -- Other Witness+ [ver, OP_PUSHDATA bs _]+ | isJust (opWitnessVersion ver)+ && BS.length bs >= 2+ && BS.length bs <= 40 ->+ Right $ PayWitness (fromJust (opWitnessVersion ver)) bs -- Provably unspendable data carrier output [OP_RETURN, OP_PUSHDATA bs _] -> Right $ DataCarrier bs -- Pay to MultiSig Keys _ -> matchPayMulSig s +witnessVersionOp :: Word8 -> Maybe ScriptOp+witnessVersionOp 0 = Just OP_0+witnessVersionOp 1 = Just OP_1+witnessVersionOp 2 = Just OP_2+witnessVersionOp 3 = Just OP_3+witnessVersionOp 4 = Just OP_4+witnessVersionOp 5 = Just OP_5+witnessVersionOp 6 = Just OP_6+witnessVersionOp 7 = Just OP_7+witnessVersionOp 8 = Just OP_8+witnessVersionOp 9 = Just OP_9+witnessVersionOp 10 = Just OP_10+witnessVersionOp 11 = Just OP_11+witnessVersionOp 12 = Just OP_12+witnessVersionOp 13 = Just OP_13+witnessVersionOp 14 = Just OP_14+witnessVersionOp 15 = Just OP_15+witnessVersionOp 16 = Just OP_16++opWitnessVersion :: ScriptOp -> Maybe Word8+opWitnessVersion OP_0 = Just 0+opWitnessVersion OP_1 = Just 1+opWitnessVersion OP_2 = Just 2+opWitnessVersion OP_3 = Just 3+opWitnessVersion OP_4 = Just 4+opWitnessVersion OP_5 = Just 5+opWitnessVersion OP_6 = Just 6+opWitnessVersion OP_7 = Just 7+opWitnessVersion OP_8 = Just 8+opWitnessVersion OP_9 = Just 9+opWitnessVersion OP_10 = Just 10+opWitnessVersion OP_11 = Just 11+opWitnessVersion OP_12 = Just 12+opWitnessVersion OP_13 = Just 13+opWitnessVersion OP_14 = Just 14+opWitnessVersion OP_15 = Just 15+opWitnessVersion OP_16 = Just 16+opWitnessVersion _ = Nothing++ -- | Similar to 'decodeOutput' but decodes from a 'ByteString'. decodeOutputBS :: ByteString -> Either String ScriptOutput decodeOutputBS = decodeOutput <=< S.decode@@ -161,7 +218,11 @@ (PayPK k) -> [opPushData $ S.encode k, OP_CHECKSIG] -- Pay to PubKey Hash Address (PayPKHash h) ->- [ OP_DUP, OP_HASH160, opPushData $ S.encode h, OP_EQUALVERIFY, OP_CHECKSIG]+ [ OP_DUP+ , OP_HASH160+ , opPushData $ S.encode h+ , OP_EQUALVERIFY, OP_CHECKSIG+ ] -- Pay to MultiSig Keys (PayMulSig ps r) | r <= length ps ->@@ -178,6 +239,11 @@ [ OP_0, opPushData $ S.encode h ] (PayWitnessScriptHash h) -> [ OP_0, opPushData $ S.encode h ]+ (PayWitness v h) ->+ [ case witnessVersionOp v of+ Nothing -> error "encodeOutput: invalid witness version"+ Just c -> c+ , opPushData h ] -- Provably unspendable output (DataCarrier d) -> [OP_RETURN, opPushData d]
src/Haskoin/Util/Arbitrary/Address.hs view
@@ -9,6 +9,7 @@ -} module Haskoin.Util.Arbitrary.Address where +import qualified Data.ByteString as B import Haskoin.Address import Haskoin.Constants import Haskoin.Util.Arbitrary.Crypto@@ -26,6 +27,7 @@ , arbitraryScriptAddress , arbitraryWitnessPubKeyAddress , arbitraryWitnessScriptAddress+ , arbitraryWitnessAddress ] -- | Arbitrary valid combination of (Network, Address)@@ -51,3 +53,11 @@ -- | Arbitrary pay-to-witness script hash arbitraryWitnessScriptAddress :: Gen Address arbitraryWitnessScriptAddress = WitnessPubKeyAddress <$> arbitraryHash160++arbitraryWitnessAddress :: Gen Address+arbitraryWitnessAddress = do+ ver <- choose (0, 16)+ len <- choose (2, 40)+ ws <- vectorOf len arbitrary+ let bs = B.pack ws+ return $ WitnessAddress ver bs
src/Haskoin/Util/Arbitrary/Script.hs view
@@ -10,6 +10,7 @@ module Haskoin.Util.Arbitrary.Script where import Crypto.Secp256k1+import qualified Data.ByteString as B import Data.Maybe import Data.Word import Haskoin.Address@@ -239,7 +240,10 @@ , arbitraryDCOutput ] ++ if getSegWit net- then [arbitraryWPKHashOutput, arbitraryWSHOutput]+ then [ arbitraryWPKHashOutput+ , arbitraryWSHOutput+ , arbitraryWitOutput+ ] else [] -- | Arbitrary 'ScriptOutput' of type 'PayPK', 'PayPKHash' or 'PayMS'@@ -267,6 +271,14 @@ -- | Arbitrary 'PayWitnessScriptHash' output. arbitraryWSHOutput :: Gen ScriptOutput arbitraryWSHOutput = PayWitnessScriptHash <$> arbitraryHash256++arbitraryWitOutput :: Gen ScriptOutput+arbitraryWitOutput = do+ ver <- choose (0, 16)+ len <- choose (2, 40)+ ws <- vectorOf len arbitrary+ let bs = B.pack ws+ return $ PayWitness ver bs -- | Arbitrary 'ScriptOutput' of type 'PayMS'. arbitraryMSOutput :: Gen ScriptOutput