haskoin-core 0.4.0 → 0.4.1
raw patch · 7 files changed
+104/−22 lines, 7 filesdep +binarydep ~HUnitdep ~QuickCheckdep ~aesonPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: binary
Dependency ranges changed: HUnit, QuickCheck, aeson
API changes (from Hackage documentation)
+ Network.Haskoin.Internals: DataCarrier :: !ByteString -> ScriptOutput
+ Network.Haskoin.Internals: [getOutputData] :: ScriptOutput -> !ByteString
+ Network.Haskoin.Internals: cltvDecodeInt :: StackValue -> Maybe Word32
+ Network.Haskoin.Internals: cltvEncodeInt :: Word32 -> StackValue
+ Network.Haskoin.Internals: decodeFullInt :: StackValue -> Maybe Int64
+ Network.Haskoin.Internals: isDataCarrier :: ScriptOutput -> Bool
+ Network.Haskoin.Script: DataCarrier :: !ByteString -> ScriptOutput
+ Network.Haskoin.Script: [getOutputData] :: ScriptOutput -> !ByteString
- Network.Haskoin.Crypto: signMsg :: Hash256 -> PrvKey -> Signature
+ Network.Haskoin.Crypto: signMsg :: Hash256 -> PrvKeyI c -> Signature
- Network.Haskoin.Crypto: verifySig :: Hash256 -> Signature -> PubKey -> Bool
+ Network.Haskoin.Crypto: verifySig :: Hash256 -> Signature -> PubKeyI c -> Bool
- Network.Haskoin.Internals: signMsg :: Hash256 -> PrvKey -> Signature
+ Network.Haskoin.Internals: signMsg :: Hash256 -> PrvKeyI c -> Signature
- Network.Haskoin.Internals: verifySig :: Hash256 -> Signature -> PubKey -> Bool
+ Network.Haskoin.Internals: verifySig :: Hash256 -> Signature -> PubKeyI c -> Bool
Files
- Network/Haskoin/Crypto/ECDSA.hs +2/−2
- Network/Haskoin/Script/Evaluator.hs +49/−9
- Network/Haskoin/Script/Parser.hs +13/−0
- Network/Haskoin/Test/Script.hs +11/−1
- haskoin-core.cabal +9/−8
- tests/Network/Haskoin/Crypto/Units.hs +3/−2
- tests/Network/Haskoin/Script/Tests.hs +17/−0
Network/Haskoin/Crypto/ECDSA.hs view
@@ -91,11 +91,11 @@ -- <http://www.secg.org/sec1-v2.pdf Section 4.1.3> -- | Sign a message-signMsg :: Hash256 -> PrvKey -> Signature+signMsg :: Hash256 -> PrvKeyI c -> Signature signMsg h d = Signature $ EC.signMsg (prvKeySecKey d) (hashToMsg h) -- | Verify an ECDSA signature-verifySig :: Hash256 -> Signature -> PubKey -> Bool+verifySig :: Hash256 -> Signature -> PubKeyI c -> Bool verifySig h s q = EC.verifySig p g m where
Network/Haskoin/Script/Evaluator.hs view
@@ -19,6 +19,9 @@ -- * Helper functions , encodeInt , decodeInt+, decodeFullInt+, cltvEncodeInt+, cltvDecodeInt , encodeBool , decodeBool , runStack@@ -41,7 +44,7 @@ import Data.Maybe (isJust, mapMaybe) import Data.Serialize (decode, encode) import Data.String.Conversions (cs)-import Data.Word (Word64, Word8)+import Data.Word (Word64, Word32, Word8) import Network.Haskoin.Crypto import Network.Haskoin.Script.SigHash import Network.Haskoin.Script.Types@@ -156,6 +159,9 @@ -- | Encoding function for the stack value format of integers. Most -- significant bit defines sign.+-- Note that this function will encode any Int64 into a StackValue,+-- thus producing stack-encoded integers which are not valid numeric+-- opcodes, as they exceed 4 bytes in length. encodeInt :: Int64 -> StackValue encodeInt i = prefix $ encod (fromIntegral $ abs i) [] where encod :: Word64 -> StackValue -> StackValue@@ -167,16 +173,50 @@ | i < 0 = init xs ++ [setBit (last xs) 7] | otherwise = xs --- | Inverse of `encodeInt`.+-- | Decode an Int64 from the stack value integer format.+-- Inverse of `encodeInt`.+-- Note that only integers decoded by 'decodeInt' are valid+-- numeric opcodes (numeric opcodes can only be up to 4 bytes in size).+-- However, in the case of eg. CHECKLOCKTIMEVERIFY, we need to+-- be able to encode and decode stack integers up to+-- (maxBound :: Word32), which are 5 bytes.+decodeFullInt :: StackValue -> Maybe Int64+decodeFullInt bytes+ | length bytes > 8 = Nothing+ | otherwise = Just $ sign' (decodeW bytes)+ where decodeW [] = 0+ decodeW [x] = fromIntegral $ clearBit x 7+ decodeW (x:xs) = fromIntegral x + decodeW xs `shiftL` 8+ sign' i | null bytes = 0+ | testBit (last bytes) 7 = -i+ | otherwise = i++-- | Used for decoding numeric opcodes. Will not return+-- an integer that takes up more than+-- 4 bytes on the stack (the size limit for numeric opcodes).+-- The naming is kept for backwards compatibility. decodeInt :: StackValue -> Maybe Int64 decodeInt bytes | length bytes > 4 = Nothing- | otherwise = Just $ sign' (decodeW bytes)- where decodeW [] = 0- decodeW [x] = fromIntegral $ clearBit x 7- decodeW (x:xs) = fromIntegral x + decodeW xs `shiftL` 8- sign' i | null bytes = 0- | testBit (last bytes) 7 = -i- | otherwise = i+ | otherwise = decodeFullInt bytes++-- | Decode the integer argument to OP_CHECKLOCKTIMEVERIFY (CLTV)+-- from a stack value.+-- The full uint32 range is needed in order to represent timestamps+-- for use with CLTV. Reference:+-- https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#Detailed_Specification+cltvDecodeInt :: StackValue -> Maybe Word32+cltvDecodeInt bytes+ | length bytes > 5 = Nothing+ | otherwise = decodeFullInt bytes >>= uint32Bounds+ where+ uint32Bounds :: Int64 -> Maybe Word32+ uint32Bounds i64+ | i64 < 0 || i64 > fromIntegral (maxBound :: Word32) = Nothing+ | otherwise = Just $ fromIntegral i64++-- | Helper function for encoding the argument to OP_CHECKLOCKTIMEVERIFY+cltvEncodeInt :: Word32 -> StackValue+cltvEncodeInt = encodeInt . fromIntegral -- | Conversion of StackValue to Bool (true if non-zero). decodeBool :: StackValue -> Bool
Network/Haskoin/Script/Parser.hs view
@@ -25,6 +25,7 @@ , isSpendPKHash , isSpendMulSig , isScriptHashInput+, isDataCarrier ) where import Control.Applicative ((<|>))@@ -60,6 +61,8 @@ } -- | Pay to a script hash. | PayScriptHash { getOutputAddress :: !Address }+ -- | Provably unspendable data carrier.+ | DataCarrier { getOutputData :: !ByteString } deriving (Eq, Show, Read) instance FromJSON ScriptOutput where@@ -75,6 +78,7 @@ rnf (PayPKHash a) = rnf a rnf (PayMulSig k r) = rnf k `seq` rnf r rnf (PayScriptHash a) = rnf a+ rnf (DataCarrier a) = rnf a -- | Returns True if the script is a pay to public key output. isPayPK :: ScriptOutput -> Bool@@ -96,6 +100,11 @@ isPayScriptHash (PayScriptHash _) = True isPayScriptHash _ = False +-- | Returns True if the script is an OP_RETURN "datacarrier" output+isDataCarrier :: ScriptOutput -> Bool+isDataCarrier (DataCarrier _) = True+isDataCarrier _ = False+ -- | Computes a script address from a script output. This address can be used -- in a pay to script hash output. scriptAddr :: ScriptOutput -> Address@@ -141,6 +150,8 @@ ] (PubKeyAddress _) -> error "encodeOutput: PubKeyAddress is invalid in PayScriptHash"+ -- Provably unspendable output+ (DataCarrier d) -> [OP_RETURN, opPushData d] -- | Similar to 'encodeOutput' but encodes to a ByteString encodeOutputBS :: ScriptOutput -> ByteString@@ -158,6 +169,8 @@ -- Pay to Script Hash [OP_HASH160, OP_PUSHDATA bs _, OP_EQUAL] -> (PayScriptHash . ScriptAddress) <$> decode bs+ -- Provably unspendable data carrier output+ [OP_RETURN, OP_PUSHDATA bs _] -> Right $ DataCarrier bs -- Pay to MultiSig Keys _ -> matchPayMulSig s
Network/Haskoin/Test/Script.hs view
@@ -257,10 +257,11 @@ , arbitrary >>= \(ArbitraryPKHashOutput o) -> return o , arbitrary >>= \(ArbitraryMSOutput o) -> return o , arbitrary >>= \(ArbitrarySHOutput o) -> return o+ , arbitrary >>= \(ArbitraryDCOutput o) -> return o ] -- | Arbitrary ScriptOutput of type PayPK, PayPKHash or PayMS--- (Not PayScriptHash)+-- (Not PayScriptHash or DataCarrier) newtype ArbitrarySimpleOutput = ArbitrarySimpleOutput ScriptOutput deriving (Eq, Show, Read) @@ -321,6 +322,15 @@ arbitrary = do ArbitraryScriptAddress a <- arbitrary return $ ArbitrarySHOutput $ PayScriptHash a++-- | Arbitrary ScriptOutput of type DataCarrier+newtype ArbitraryDCOutput = ArbitraryDCOutput ScriptOutput+ deriving (Eq, Show, Read)++instance Arbitrary ArbitraryDCOutput where+ arbitrary = do+ ArbitraryNotNullByteString bs <- arbitrary+ return $ ArbitraryDCOutput $ DataCarrier bs -- | Arbitrary ScriptInput newtype ArbitraryScriptInput = ArbitraryScriptInput ScriptInput
haskoin-core.cabal view
@@ -1,5 +1,5 @@ name: haskoin-core-version: 0.4.0+version: 0.4.1 synopsis: Implementation of the core Bitcoin protocol features. description:@@ -22,12 +22,12 @@ 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+tested-with: GHC==8.0.2 stability: stable license: PublicDomain license-file: UNLICENSE author: Philippe Laprade, Jean-Pierre Rupp-maintainer: plaprade+hackage@gmail.com+maintainer: xenog@protonmail.com category: Bitcoin, Finance, Network build-type: Simple cabal-version: >= 1.9.2@@ -82,7 +82,7 @@ DeriveDataTypeable GADTs - build-depends: aeson >= 0.7 && < 0.12+ build-depends: aeson >= 0.7 && < 1.1 , base >= 4.8 && < 5 , byteable >= 0.1 && < 0.2 , bytestring >= 0.10 && < 0.11@@ -97,7 +97,7 @@ , murmur3 >= 1.0 && < 1.1 , network >= 2.6 && < 2.7 , pbkdf >= 1.1 && < 1.2- , QuickCheck >= 2.6 && < 2.9+ , QuickCheck >= 2.6 && < 2.10 , split >= 0.2 && < 0.3 , text >= 0.11 && < 1.3 , time >= 1.4 && < 1.7@@ -138,16 +138,17 @@ Network.Haskoin.Json.Tests Network.Haskoin.Cereal.Tests - build-depends: aeson >= 0.7 && < 0.12+ build-depends: aeson >= 0.7 && < 1.1 , base >= 4.8 && < 5+ , binary >= 0.8 && < 0.9 , bytestring >= 0.10 && < 0.11 , cereal >= 0.5 && < 0.6 , containers >= 0.5 && < 0.6 , haskoin-core , mtl >= 2.2 && < 2.3 , split >= 0.2 && < 0.3- , HUnit >= 1.2 && < 1.4- , QuickCheck >= 2.6 && < 2.9+ , HUnit >= 1.2 && < 1.6+ , QuickCheck >= 2.6 && < 2.10 , test-framework >= 0.8 && < 0.9 , test-framework-quickcheck2 >= 0.3 && < 0.4 , test-framework-hunit >= 0.3 && < 0.4
tests/Network/Haskoin/Crypto/Units.hs view
@@ -10,8 +10,9 @@ import Data.Maybe (fromJust, isJust, isNothing) import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy as B +import qualified Data.Binary as Bin import qualified Data.ByteString.Char8 as C (pack)-import Data.Serialize (put, runPut) import qualified Crypto.Secp256k1 as EC (SecKey, exportCompactSig) @@ -244,4 +245,4 @@ msg' = hash256 msg prv' = makePrvKey prv compact = EC.exportCompactSig g- res = runPut $ put compact+ res = B.toStrict $ Bin.encode compact
tests/Network/Haskoin/Script/Tests.hs view
@@ -51,6 +51,8 @@ , dumpStack , decodeInt , encodeInt+ , decodeFullInt+ , cltvDecodeInt , decodeBool , encodeBool , execScript@@ -77,6 +79,8 @@ ] , testGroup "Integer Types" [ testProperty "decodeInt . encodeInt Int" testEncodeInt+ , testProperty "decodeFullInt . encodeInt Int" testEncodeInt64+ , testProperty "cltvDecodeInt . encodeInt Int" testEncodeCltv , testProperty "decodeBool . encodeBool Bool" testEncodeBool ] , testFile "Canonical Valid Script Test Cases"@@ -166,6 +170,19 @@ | otherwise = i' == Just i where i' = decodeInt $ encodeInt i++testEncodeCltv :: Int64 -> Bool+testEncodeCltv i+ -- As 'cltvEncodeInt' is just a wrapper for 'encodeInt',+ -- we use 'encodeInt' for encoding, to simultaneously+ -- test the handling of out-of-range integers by 'cltvDecodeInt'.+ | i < 0 || i > fromIntegral (maxBound :: Word32) =+ isNothing $ cltvDecodeInt (encodeInt i)+ | otherwise =+ cltvDecodeInt (encodeInt i) == Just (fromIntegral i)++testEncodeInt64 :: Int64 -> Bool+testEncodeInt64 i = decodeFullInt (encodeInt i) == Just i testEncodeBool :: Bool -> Bool testEncodeBool b = decodeBool (encodeBool b) == b