diff --git a/bitcoin.cabal b/bitcoin.cabal index 2cf10f3c..604cbdaf 100644 --- a/bitcoin.cabal +++ b/bitcoin.cabal @@ -93,7 +93,6 @@ library src build-depends: QuickCheck >=2.13.2 - , aeson >=1.4.6.0 , array >=0.5.4.0 , base >=4.9 && <5 , base16 >=0.3.0.1 @@ -107,13 +106,12 @@ library , entropy >=0.4.1.5 , hashable >=1.3.0.0 , hspec >=2.7.1 + , libsecp256k1 >=0.1.0 , memory >=0.15.0 - , mtl >=2.2.2 , murmur3 >=1.0.3 , network >=3.1.1.1 , safe >=0.3.18 , scientific >=0.3.6.2 - , secp256k1-haskell >=0.4.0 , split >=0.2.3.3 , string-conversions >=0.4.0.1 , text >=1.2.3.0 @@ -147,7 +145,6 @@ test-suite spec build-depends: HUnit >=1.6.0.0 , QuickCheck >=2.13.2 - , aeson >=1.4.6.0 , array >=0.5.4.0 , base >=4.9 && <5 , base16 >=0.3.0.1 @@ -165,13 +162,12 @@ test-suite spec , hspec >=2.7.1 , lens >=4.18.1 , lens-aeson >=1.1 + , libsecp256k1 >=0.1.0 , memory >=0.15.0 - , mtl >=2.2.2 , murmur3 >=1.0.3 , network >=3.1.1.1 , safe >=0.3.18 , scientific >=0.3.6.2 - , secp256k1-haskell >=0.4.0 , split >=0.2.3.3 , string-conversions >=0.4.0.1 , text >=1.2.3.0 diff --git a/package.yaml b/package.yaml index 9c26e25b..95825335 100644 --- a/package.yaml +++ b/package.yaml @@ -19,7 +19,6 @@ extra-source-files: - README.md - CHANGELOG.md dependencies: - - aeson >= 1.4.6.0 - array >= 0.5.4.0 - base >=4.9 && <5 - base16 >= 0.3.0.1 @@ -34,14 +33,13 @@ dependencies: - hashable >= 1.3.0.0 - hspec >= 2.7.1 - memory >= 0.15.0 - - mtl >= 2.2.2 - murmur3 >= 1.0.3 - network >= 3.1.1.1 - QuickCheck >= 2.13.2 - split >= 0.2.3.3 - safe >= 0.3.18 - scientific >= 0.3.6.2 - - secp256k1-haskell >= 0.4.0 + - libsecp256k1 >= 0.1.0 - string-conversions >= 0.4.0.1 - text >= 1.2.3.0 - time >= 1.9.3 diff --git a/src/Bitcoin/Address.hs b/src/Bitcoin/Address.hs index edf305e6..29f83a7c 100644 --- a/src/Bitcoin/Address.hs +++ b/src/Bitcoin/Address.hs @@ -22,9 +22,6 @@ module Bitcoin.Address ( textToAddr, bech32ToAddr, base58ToAddr, - addrToJSON, - addrToEncoding, - addrFromJSON, pubKeyAddr, pubKeyWitnessAddr, pubKeyCompatWitnessAddr, @@ -46,13 +43,17 @@ module Bitcoin.Address ( module Bitcoin.Address.Bech32, ) where +import Bitcoin.Address.Base58 +import Bitcoin.Address.Bech32 +import Bitcoin.Crypto +import Bitcoin.Data +import Bitcoin.Keys.Common +import Bitcoin.Script +import Bitcoin.Util import Control.Applicative import Control.Arrow (second) import Control.DeepSeq import Control.Monad -import Data.Aeson as A -import Data.Aeson.Encoding as A -import Data.Aeson.Types import Data.Binary (Binary (..)) import Data.ByteString (ByteString) import qualified Data.ByteString as B @@ -66,13 +67,6 @@ import Data.Text (Text) import qualified Data.Text as T import Data.Word (Word8) import GHC.Generics (Generic) -import Bitcoin.Address.Base58 -import Bitcoin.Address.Bech32 -import Bitcoin.Crypto -import Bitcoin.Data -import Bitcoin.Keys.Common -import Bitcoin.Script -import Bitcoin.Util -- | Address format for Bitcoin @@ -181,24 +175,6 @@ isWitnessAddress WitnessAddress{} = True isWitnessAddress _ = False -addrToJSON :: Network -> Address -> Value -addrToJSON net a = toJSON (addrToText net a) - - -addrToEncoding :: Network -> Address -> Encoding -addrToEncoding net = maybe null_ text . addrToText net - - --- | JSON parsing for Bitcoin addresses. Works with 'Base58', and --- 'Bech32'. -addrFromJSON :: Network -> Value -> Parser Address -addrFromJSON net = - withText "address" $ \t -> - case textToAddr net t of - Nothing -> fail "could not decode address" - Just x -> return x - - -- | Convert address to human-readable string. Uses 'Base58', or 'Bech32' -- depending on network. addrToText :: Network -> Address -> Maybe Text diff --git a/src/Bitcoin/Block/Common.hs b/src/Bitcoin/Block/Common.hs index 3519e719..50fc3eb9 100644 --- a/src/Bitcoin/Block/Common.hs +++ b/src/Bitcoin/Block/Common.hs @@ -26,20 +26,12 @@ module Bitcoin.Block.Common ( encodeCompact, ) where +import Bitcoin.Crypto.Hash +import Bitcoin.Network.Common +import Bitcoin.Transaction.Common +import Bitcoin.Util import Control.DeepSeq import Control.Monad (forM_, liftM2, mzero, replicateM, (<=<)) -import Data.Aeson ( - FromJSON (..), - ToJSON (..), - Value (..), - object, - toJSON, - withObject, - withText, - (.:), - (.=), - ) -import Data.Aeson.Encoding (pairs, unsafeToEncoding) import Data.Binary (Binary (..)) import Data.Bits (shiftL, shiftR, (.&.), (.|.)) import qualified Data.ByteString as B @@ -66,10 +58,6 @@ import Data.String.Conversions (cs) import Data.Text (Text) import Data.Word (Word32) import GHC.Generics (Generic) -import Bitcoin.Crypto.Hash -import Bitcoin.Network.Common -import Bitcoin.Transaction.Common -import Bitcoin.Util import qualified Text.Read as R @@ -111,17 +99,6 @@ instance Binary Block where put = serialize -instance ToJSON Block where - toJSON (Block h t) = object ["header" .= h, "transactions" .= t] - toEncoding (Block h t) = pairs $ "header" .= h <> "transactions" .= t - - -instance FromJSON Block where - parseJSON = - withObject "Block" $ \o -> - Block <$> o .: "header" <*> o .: "transactions" - - -- | Block header hash. To be serialized reversed for display purposes. newtype BlockHash = BlockHash { getBlockHash :: Hash256 @@ -155,21 +132,6 @@ instance IsString BlockHash where in fromMaybe e $ hexToBlockHash $ cs s -instance FromJSON BlockHash where - parseJSON = - withText "BlockHash" $ - maybe mzero return . hexToBlockHash - - -instance ToJSON BlockHash where - toJSON = String . blockHashToHex - toEncoding h = - unsafeToEncoding $ - char7 '"' - <> hexBuilder (BL.reverse (runPutL (serialize h))) - <> char7 '"' - - -- | Block hashes are reversed with respect to the in-memory byte order in a -- block hash when displayed. blockHashToHex :: BlockHash -> Text @@ -212,43 +174,6 @@ data BlockHeader = BlockHeader deriving (Eq, Ord, Show, Read, Generic, Hashable, NFData) --- 80 bytes - -instance ToJSON BlockHeader where - toJSON (BlockHeader v p m t b n) = - object - [ "version" .= v - , "prevblock" .= p - , "merkleroot" .= encodeHex (runPutS (serialize m)) - , "timestamp" .= t - , "bits" .= b - , "nonce" .= n - ] - toEncoding (BlockHeader v p m t b n) = - pairs - ( "version" .= v - <> "prevblock" .= p - <> "merkleroot" .= encodeHex (runPutS (serialize m)) - <> "timestamp" .= t - <> "bits" .= b - <> "nonce" .= n - ) - - -instance FromJSON BlockHeader where - parseJSON = - withObject "BlockHeader" $ \o -> - BlockHeader - <$> o .: "version" - <*> o .: "prevblock" - <*> (f =<< o .: "merkleroot") - <*> o .: "timestamp" - <*> o .: "bits" - <*> o .: "nonce" - where - f = maybe mzero return . (eitherToMaybe . runGetS deserialize <=< decodeHex) - - instance Serial BlockHeader where deserialize = do v <- getWord32le diff --git a/src/Bitcoin/Block/Headers.hs b/src/Bitcoin/Block/Headers.hs index 31998f34..8fca8cf9 100644 --- a/src/Bitcoin/Block/Headers.hs +++ b/src/Bitcoin/Block/Headers.hs @@ -60,22 +60,18 @@ module Bitcoin.Block.Headers ( lastSmallerOrEqual, ) where +import Bitcoin.Block.Common +import Bitcoin.Crypto +import Bitcoin.Data +import Bitcoin.Transaction.Genesis +import Bitcoin.Util import Control.Applicative ((<|>)) import Control.DeepSeq import Control.Monad (guard, mzero, unless, when) -import Control.Monad.Except ( - ExceptT (..), - runExceptT, - throwError, - ) -import Control.Monad.State.Strict as State ( - StateT, - get, - gets, - lift, - modify, - ) +import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Except (ExceptT (..), runExceptT, throwE) import Control.Monad.Trans.Maybe +import Control.Monad.Trans.State.Strict as State (StateT, get, gets, modify) import Data.Binary (Binary (..)) import Data.Bits (shiftL, shiftR, (.&.)) import qualified Data.ByteString as B @@ -97,11 +93,6 @@ import Data.Serialize (Serialize (..)) import Data.Typeable (Typeable) import Data.Word (Word32, Word64) import GHC.Generics (Generic) -import Bitcoin.Block.Common -import Bitcoin.Crypto -import Bitcoin.Data -import Bitcoin.Transaction.Genesis -import Bitcoin.Util -- | Short version of the block hash. Uses the good end of the hash (the part @@ -323,7 +314,7 @@ connectBlocks _ _ [] = return $ Right [] connectBlocks net t bhs@(bh : _) = runExceptT $ do unless (chained bhs) $ - throwError "Blocks to connect do not form a chain" + throwE "Blocks to connect do not form a chain" par <- maybeToExceptT "Could not get parent block" @@ -347,13 +338,13 @@ connectBlocks net t bhs@(bh : _) = case skM of Just sk -> return sk Nothing -> - throwError $ + throwE $ "BUG: Could not get skip for block " ++ show (headerHash $ nodeHeader par) | otherwise = do let sn = ls !! fromIntegral (nodeHeight par - sh) when (nodeHeight sn /= sh) $ - throwError "BUG: Node height not right in skip" + throwE "BUG: Node height not right in skip" return sn where sh = skipHeight (nodeHeight par + 1) @@ -394,7 +385,7 @@ connectBlock net t bh = case skM of Just sk -> return sk Nothing -> - throwError $ + throwE $ "BUG: Could not get skip for block " ++ show (headerHash $ nodeHeader par) bb <- lift getBestBlockHeader diff --git a/src/Bitcoin/Crypto/Hash.hs b/src/Bitcoin/Crypto/Hash.hs index 814edfad..a6daa3f5 100644 --- a/src/Bitcoin/Crypto/Hash.hs +++ b/src/Bitcoin/Crypto/Hash.hs @@ -28,6 +28,7 @@ module Bitcoin.Crypto.Hash ( initTaggedHash, ) where +import Bitcoin.Util import Control.DeepSeq import Crypto.Hash ( Context, @@ -57,7 +58,6 @@ import Data.String (IsString, fromString) import Data.String.Conversions (cs) import Data.Word (Word32) import GHC.Generics (Generic) -import Bitcoin.Util import Text.Read as R @@ -280,8 +280,6 @@ join512 (a, b) = -- | Initialize tagged hash specified in BIP340 --- --- @since 0.21.0 initTaggedHash :: -- | Hash tag ByteString -> diff --git a/src/Bitcoin/Crypto/Signature.hs b/src/Bitcoin/Crypto/Signature.hs index 92f3776f..97a83d69 100644 --- a/src/Bitcoin/Crypto/Signature.hs +++ b/src/Bitcoin/Crypto/Signature.hs @@ -14,9 +14,9 @@ module Bitcoin.Crypto.Signature ( verifyHashSig, isCanonicalHalfOrder, decodeStrictSig, - exportSig, ) where +import Bitcoin.Crypto.Hash import Control.Monad (guard, unless, when) import Crypto.Secp256k1 import Data.Binary (Binary (..)) @@ -27,32 +27,23 @@ import Data.Bytes.Put import Data.Bytes.Serial import Data.Maybe (fromMaybe, isNothing) import Data.Serialize (Serialize (..)) -import Bitcoin.Crypto.Hash import Numeric (showHex) --- | Convert 256-bit hash into a 'Msg' for signing or verification. -hashToMsg :: Hash256 -> Msg -hashToMsg = - fromMaybe e . msg . runPutS . serialize - where - e = error "Could not convert 32-byte hash to secp256k1 message" - - -- | Sign a 256-bit hash using secp256k1 elliptic curve. -signHash :: SecKey -> Hash256 -> Sig -signHash k = signMsg k . hashToMsg +signHash :: SecKey -> Hash256 -> Signature +signHash k = ecdsaSign k . fromShort . getHash256 -- | Verify an ECDSA signature for a 256-bit hash. -verifyHashSig :: Hash256 -> Sig -> PubKey -> Bool +verifyHashSig :: Hash256 -> Signature -> PubKeyXY -> Bool verifyHashSig h s p = verifySig p norm (hashToMsg h) where norm = fromMaybe s (normalizeSig s) -- | Deserialize an ECDSA signature as commonly encoded in Bitcoin. -getSig :: MonadGet m => m Sig +getSig :: MonadGet m => m Signature getSig = do l <- lookAhead $ do @@ -72,17 +63,17 @@ getSig = do -- | Serialize an ECDSA signature for Bitcoin use. -putSig :: MonadPut m => Sig -> m () +putSig :: MonadPut m => Signature -> m () putSig s = putByteString $ exportSig s -- | Is canonical half order. -isCanonicalHalfOrder :: Sig -> Bool +isCanonicalHalfOrder :: Signature -> Bool isCanonicalHalfOrder = isNothing . normalizeSig -- | Decode signature strictly. -decodeStrictSig :: ByteString -> Maybe Sig +decodeStrictSig :: ByteString -> Maybe Signature decodeStrictSig bs = do g <- importSig bs -- diff --git a/src/Bitcoin/Keys/Common.hs b/src/Bitcoin/Keys/Common.hs index 1fca3e16..5aa9f5e0 100644 --- a/src/Bitcoin/Keys/Common.hs +++ b/src/Bitcoin/Keys/Common.hs @@ -31,17 +31,13 @@ module Bitcoin.Keys.Common ( toWif, ) where +import Bitcoin.Address.Base58 +import Bitcoin.Crypto.Hash +import Bitcoin.Data +import Bitcoin.Util import Control.DeepSeq import Control.Monad (guard, mzero, (<=<)) import Crypto.Secp256k1 -import Data.Aeson ( - FromJSON, - ToJSON (..), - Value (String), - parseJSON, - withText, - ) -import Data.Aeson.Encoding (unsafeToEncoding) import Data.Binary (Binary (..)) import Data.ByteString (ByteString) import qualified Data.ByteString as BS @@ -55,10 +51,6 @@ import Data.Serialize (Serialize (..)) import Data.String (IsString, fromString) import Data.String.Conversions (cs) import GHC.Generics (Generic) -import Bitcoin.Address.Base58 -import Bitcoin.Crypto.Hash -import Bitcoin.Data -import Bitcoin.Util -- | Elliptic curve public key type with expected serialized compression flag. @@ -76,21 +68,6 @@ instance IsString PubKeyI where e = error "Could not decode public key" -instance ToJSON PubKeyI where - toJSON = String . encodeHex . runPutS . serialize - toEncoding s = - unsafeToEncoding $ - char7 '"' - <> hexBuilder (runPutL (serialize s)) - <> char7 '"' - - -instance FromJSON PubKeyI where - parseJSON = - withText "PubKeyI" $ - maybe mzero return . ((eitherToMaybe . runGetS deserialize) <=< decodeHex) - - instance Serial PubKeyI where deserialize = s >>= \case diff --git a/src/Bitcoin/Keys/Extended.hs b/src/Bitcoin/Keys/Extended.hs index bb13ed16..53172dd1 100644 --- a/src/Bitcoin/Keys/Extended.hs +++ b/src/Bitcoin/Keys/Extended.hs @@ -36,13 +36,7 @@ module Bitcoin.Keys.Extended ( xPubWitnessAddr, xPubCompatWitnessAddr, xPubExport, - xPubToJSON, - xPubToEncoding, - xPubFromJSON, xPrvExport, - xPrvToJSON, - xPrvToEncoding, - xPrvFromJSON, xPubImport, xPrvImport, xPrvWif, @@ -100,21 +94,22 @@ module Bitcoin.Keys.Extended ( concatBip32Segments, ) where +import Bitcoin.Address +import Bitcoin.Crypto.Hash +import Bitcoin.Data +import Bitcoin.Keys.Common +import Bitcoin.Keys.Extended.Internal ( + Fingerprint (..), + fingerprintToText, + textToFingerprint, + ) +import Bitcoin.Script +import Bitcoin.Util import Control.Applicative import Control.DeepSeq import Control.Exception (Exception, throw) import Control.Monad (guard, mzero, unless, (<=<)) import Crypto.Secp256k1 -import Data.Aeson as A ( - FromJSON, - ToJSON (..), - Value (String), - parseJSON, - toJSON, - withText, - ) -import Data.Aeson.Encoding (Encoding, text) -import Data.Aeson.Types (Parser) import Data.Binary (Binary (get, put)) import Data.Bits (clearBit, setBit, testBit) import Data.ByteString (ByteString) @@ -135,17 +130,6 @@ import qualified Data.Text as Text import Data.Typeable (Typeable) import Data.Word (Word32, Word8) import GHC.Generics (Generic) -import Bitcoin.Address -import Bitcoin.Crypto.Hash -import Bitcoin.Data -import Bitcoin.Keys.Common -import Bitcoin.Keys.Extended.Internal ( - Fingerprint (..), - fingerprintToText, - textToFingerprint, - ) -import Bitcoin.Script -import Bitcoin.Util import Text.Read as R import Text.Read.Lex @@ -211,23 +195,6 @@ instance Serialize XPrvKey where get = deserialize -xPrvToJSON :: Network -> XPrvKey -> Value -xPrvToJSON net = A.String . xPrvExport net - - -xPrvToEncoding :: Network -> XPrvKey -> Encoding -xPrvToEncoding net = text . xPrvExport net - - --- | Decode an extended private key from a JSON string -xPrvFromJSON :: Network -> Value -> Parser XPrvKey -xPrvFromJSON net = - withText "xprv" $ \t -> - case xPrvImport net t of - Nothing -> fail "could not read xprv" - Just x -> return x - - -- | Data type representing an extended BIP32 public key. data XPubKey = XPubKey { xPubDepth :: !Word8 @@ -270,24 +237,6 @@ instance Binary XPubKey where get = deserialize --- | Decode an extended public key from a JSON string -xPubFromJSON :: Network -> Value -> Parser XPubKey -xPubFromJSON net = - withText "xpub" $ \t -> - case xPubImport net t of - Nothing -> fail "could not read xpub" - Just x -> return x - - --- | Get JSON 'Value' from 'XPubKey'. -xPubToJSON :: Network -> XPubKey -> Value -xPubToJSON net = A.String . xPubExport net - - -xPubToEncoding :: Network -> XPubKey -> Encoding -xPubToEncoding net = text . xPubExport net - - -- | Build a BIP32 compatible extended private key from a bytestring. This will -- produce a root node (@depth=0@ and @parent=0@). makeXPrvKey :: ByteString -> XPrvKey @@ -922,44 +871,6 @@ instance IsString SoftPath where e = error "Could not parse soft derivation path" -instance FromJSON ParsedPath where - parseJSON = withText "ParsedPath" $ \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 $ getParsedPath p - _ -> mzero - - -instance FromJSON HardPath where - parseJSON = withText "HardPath" $ \str -> case parseHard $ cs str of - Just p -> return p - _ -> mzero - - -instance FromJSON SoftPath where - parseJSON = withText "SoftPath" $ \str -> case parseSoft $ cs str of - Just p -> return p - _ -> mzero - - -instance ToJSON (DerivPathI t) where - toJSON = A.String . cs . pathToStr - toEncoding = text . cs . pathToStr - - -instance ToJSON ParsedPath where - toJSON (ParsedPrv p) = A.String . cs . ("m" ++) . pathToStr $ p - toJSON (ParsedPub p) = A.String . cs . ("M" ++) . pathToStr $ p - toJSON (ParsedEmpty p) = A.String . cs . ("" ++) . pathToStr $ p - toEncoding (ParsedPrv p) = text . cs . ("m" ++) . pathToStr $ p - toEncoding (ParsedPub p) = text . cs . ("M" ++) . pathToStr $ p - toEncoding (ParsedEmpty p) = text . cs . ("" ++) . pathToStr $ p - - {- Parsing derivation paths of the form m/1/2'/3 or M/1/2'/3 -} -- | Type for parsing derivation paths of the form /m\/1\/2'\/3/ or diff --git a/src/Bitcoin/Keys/Extended/Internal.hs b/src/Bitcoin/Keys/Extended/Internal.hs index 50b01593..8bdc8595 100644 --- a/src/Bitcoin/Keys/Extended/Internal.hs +++ b/src/Bitcoin/Keys/Extended/Internal.hs @@ -7,15 +7,9 @@ module Bitcoin.Keys.Extended.Internal ( textToFingerprint, ) where +import Bitcoin.Util (decodeHex, encodeHex) import Control.DeepSeq (NFData) import Control.Monad ((>=>)) -import Data.Aeson ( - FromJSON, - ToJSON, - parseJSON, - toJSON, - withText, - ) import Data.Binary (Binary (..)) import Data.Bytes.Get (getWord32be) import Data.Bytes.Put (putWord32be) @@ -31,7 +25,6 @@ import qualified Data.Text as Text import Data.Typeable (Typeable) import Data.Word (Word32) import GHC.Generics (Generic) -import Bitcoin.Util (decodeHex, encodeHex) import Text.Read (readEither, readPrec) @@ -84,11 +77,3 @@ instance Binary Fingerprint where instance Serialize Fingerprint where put = serialize get = deserialize - - -instance FromJSON Fingerprint where - parseJSON = withText "Fingerprint" $ either fail pure . textToFingerprint - - -instance ToJSON Fingerprint where - toJSON = toJSON . fingerprintToText diff --git a/src/Bitcoin/Script/SigHash.hs b/src/Bitcoin/Script/SigHash.hs index db27a2d8..fb672175 100644 --- a/src/Bitcoin/Script/SigHash.hs +++ b/src/Bitcoin/Script/SigHash.hs @@ -27,9 +27,15 @@ module Bitcoin.Script.SigHash ( decodeTxSig, ) where +import Bitcoin.Crypto +import Bitcoin.Crypto.Hash +import Bitcoin.Data +import Bitcoin.Network.Common +import Bitcoin.Script.Common +import Bitcoin.Transaction.Common +import Bitcoin.Util import Control.DeepSeq import Control.Monad -import qualified Data.Aeson as J import Data.Bits import qualified Data.ByteString as BS import Data.Bytes.Get @@ -40,13 +46,6 @@ import Data.Maybe import Data.Scientific import Data.Word import GHC.Generics (Generic) -import Bitcoin.Crypto -import Bitcoin.Crypto.Hash -import Bitcoin.Data -import Bitcoin.Network.Common -import Bitcoin.Script.Common -import Bitcoin.Transaction.Common -import Bitcoin.Util -- | Constant representing a SIGHASH flag that controls what is being signed. @@ -109,17 +108,6 @@ newtype SigHash ) -instance J.FromJSON SigHash where - parseJSON = - J.withScientific "sighash" $ - maybe mzero (return . SigHash) . toBoundedInteger - - -instance J.ToJSON SigHash where - toJSON = J.Number . fromIntegral - toEncoding (SigHash n) = J.toEncoding n - - -- | SIGHASH_NONE as a byte. sigHashNone :: SigHash sigHashNone = fromIntegral $ fromEnum SIGHASH_NONE diff --git a/src/Bitcoin/Script/Standard.hs b/src/Bitcoin/Script/Standard.hs index 5288cdb2..36042d49 100644 --- a/src/Bitcoin/Script/Standard.hs +++ b/src/Bitcoin/Script/Standard.hs @@ -41,11 +41,15 @@ module Bitcoin.Script.Standard ( isScriptHashInput, ) where +import Bitcoin.Crypto +import Bitcoin.Data +import Bitcoin.Keys.Common +import Bitcoin.Script.Common +import Bitcoin.Script.SigHash +import Bitcoin.Util import Control.Applicative ((<|>)) import Control.DeepSeq import Control.Monad (guard, liftM2, (<=<)) -import qualified Data.Aeson as A -import qualified Data.Aeson.Encoding as A import Data.ByteString (ByteString) import qualified Data.ByteString as BS import Data.Bytes.Get @@ -57,12 +61,6 @@ import Data.List (sortBy) import Data.Maybe (fromJust, isJust) import Data.Word (Word8) import GHC.Generics (Generic) -import Bitcoin.Crypto -import Bitcoin.Data -import Bitcoin.Keys.Common -import Bitcoin.Script.Common -import Bitcoin.Script.SigHash -import Bitcoin.Util -- | Data type describing standard transaction output scripts. Output scripts @@ -94,19 +92,6 @@ data ScriptOutput deriving (Eq, Show, Read, Generic, Hashable, NFData) -instance A.FromJSON ScriptOutput where - parseJSON = - A.withText "scriptoutput" $ \t -> - either fail return $ - maybeToEither "scriptoutput not hex" (decodeHex t) - >>= decodeOutputBS - - -instance A.ToJSON ScriptOutput where - toJSON = A.String . encodeHex . encodeOutputBS - toEncoding = A.text . encodeHex . encodeOutputBS - - -- | Is script a pay-to-public-key output? isPayPK :: ScriptOutput -> Bool isPayPK (PayPK _) = True diff --git a/src/Bitcoin/Transaction/Builder.hs b/src/Bitcoin/Transaction/Builder.hs index 94aa7aa2..353161d0 100644 --- a/src/Bitcoin/Transaction/Builder.hs +++ b/src/Bitcoin/Transaction/Builder.hs @@ -51,7 +51,6 @@ import Bitcoin.Util import Control.Applicative ((<|>)) import Control.Arrow (first) import Control.Monad (foldM, unless) -import Control.Monad.Identity (runIdentity) import Crypto.Secp256k1 import qualified Data.ByteString as B import Data.Bytes.Get diff --git a/src/Bitcoin/Transaction/Builder/Sign.hs b/src/Bitcoin/Transaction/Builder/Sign.hs index 5e89008f..ea885017 100644 --- a/src/Bitcoin/Transaction/Builder/Sign.hs +++ b/src/Bitcoin/Transaction/Builder/Sign.hs @@ -19,19 +19,22 @@ module Bitcoin.Transaction.Builder.Sign ( sigKeys, ) where +import Bitcoin.Address (getAddrHash160, pubKeyAddr) +import Bitcoin.Crypto (Hash256, SecKey) +import Bitcoin.Crypto.Signature (signHash, verifyHashSig) +import Bitcoin.Data (Network) +import Bitcoin.Keys.Common ( + PubKeyI (..), + SecKeyI (..), + derivePubKeyI, + wrapSecKey, + ) +import Bitcoin.Script +import Bitcoin.Transaction.Common +import Bitcoin.Transaction.Segwit +import Bitcoin.Util (matchTemplate, updateIndex) import Control.DeepSeq (NFData) import Control.Monad (foldM, when) -import Data.Aeson ( - FromJSON, - ToJSON (..), - object, - pairs, - parseJSON, - withObject, - (.:), - (.:?), - (.=), - ) import Data.Bytes.Get import Data.Bytes.Put import Data.Bytes.Serial @@ -46,20 +49,6 @@ import Data.Maybe ( ) import Data.Word (Word64) import GHC.Generics (Generic) -import Bitcoin.Address (getAddrHash160, pubKeyAddr) -import Bitcoin.Crypto (Hash256, SecKey) -import Bitcoin.Crypto.Signature (signHash, verifyHashSig) -import Bitcoin.Data (Network) -import Bitcoin.Keys.Common ( - PubKeyI (..), - SecKeyI (..), - derivePubKeyI, - wrapSecKey, - ) -import Bitcoin.Script -import Bitcoin.Transaction.Common -import Bitcoin.Transaction.Segwit -import Bitcoin.Util (matchTemplate, updateIndex) -- | Data type used to specify the signing parameters of a transaction input. @@ -85,35 +74,6 @@ data SigInput = SigInput deriving (Eq, Show, Read, Generic, Hashable, NFData) -instance ToJSON SigInput where - toJSON (SigInput so val op sh rdm) = - object $ - [ "pkscript" .= so - , "value" .= val - , "outpoint" .= op - , "sighash" .= sh - ] - ++ ["redeem" .= r | r <- maybeToList rdm] - toEncoding (SigInput so val op sh rdm) = - pairs $ - "pkscript" .= so - <> "value" .= val - <> "outpoint" .= op - <> "sighash" .= sh - <> maybe mempty ("redeem" .=) rdm - - -instance FromJSON SigInput where - parseJSON = - withObject "SigInput" $ \o -> - SigInput - <$> o .: "pkscript" - <*> o .: "value" - <*> o .: "outpoint" - <*> o .: "sighash" - <*> o .:? "redeem" - - -- | Sign a transaction by providing the 'SigInput' signing parameters and a -- list of private keys. The signature is computed deterministically as defined -- in RFC-6979. @@ -167,8 +127,6 @@ signInput net tx i (sigIn@(SigInput so val _ _ rdmM), nest) key = do -- | Add the witness data of the transaction given segwit parameters for an input. --- --- @since 0.11.0.0 updatedWitnessData :: Tx -> Int -> ScriptOutput -> ScriptInput -> Either String WitnessData updatedWitnessData tx i so si | isSegwit so = updateWitness . toWitnessStack =<< calcWitnessProgram so si @@ -273,8 +231,6 @@ buildInput net tx i so val rdmM sig pub = do -- | Apply heuristics to extract the signatures for a particular input that are -- embedded in the transaction. --- --- @since 0.11.0.0 parseExistingSigs :: Network -> Tx -> ScriptOutput -> Int -> [TxSignature] parseExistingSigs net tx so i = insSigs <> witSigs where @@ -298,8 +254,6 @@ makeSignature net tx i (SigInput so val _ sh rdmM) key = -- | A function which selects the digest algorithm and parameters as appropriate --- --- @since 0.11.0.0 makeSigHash :: Network -> Tx -> diff --git a/src/Bitcoin/Transaction/Common.hs b/src/Bitcoin/Transaction/Common.hs index 885fed84..d370b127 100644 --- a/src/Bitcoin/Transaction/Common.hs +++ b/src/Bitcoin/Transaction/Common.hs @@ -24,6 +24,9 @@ module Bitcoin.Transaction.Common ( nullOutPoint, ) where +import Bitcoin.Crypto.Hash +import Bitcoin.Network.Common +import Bitcoin.Util import Control.Applicative ((<|>)) import Control.DeepSeq import Control.Monad ( @@ -36,8 +39,6 @@ import Control.Monad ( when, (<=<), ) -import Data.Aeson as A -import Data.Aeson.Encoding (unsafeToEncoding) import Data.Binary (Binary (..)) import Data.ByteString (ByteString) import qualified Data.ByteString as B @@ -54,9 +55,6 @@ import Data.String.Conversions (cs) import Data.Text (Text) import Data.Word (Word32, Word64) import GHC.Generics (Generic) -import Bitcoin.Crypto.Hash -import Bitcoin.Network.Common -import Bitcoin.Util import Text.Read as R @@ -91,21 +89,6 @@ instance IsString TxHash where in fromMaybe e $ hexToTxHash $ cs s -instance FromJSON TxHash where - parseJSON = - withText "txid" $ - maybe mzero return . hexToTxHash - - -instance ToJSON TxHash where - toJSON = A.String . txHashToHex - toEncoding h = - unsafeToEncoding $ - char7 '"' - <> hexBuilder (BL.reverse (runPutL (serialize h))) - <> char7 '"' - - -- | Transaction hash excluding signatures. nosigTxHash :: Tx -> TxHash nosigTxHash tx = @@ -284,37 +267,6 @@ putWitnessData = mapM_ putWitnessStack putByteString bs -instance FromJSON Tx where - parseJSON = withObject "Tx" $ \o -> - Tx - <$> o .: "version" - <*> o .: "inputs" - <*> o .: "outputs" - <*> (mapM (mapM f) =<< o .: "witnessdata") - <*> o .: "locktime" - where - f = maybe mzero return . decodeHex - - -instance ToJSON Tx where - toJSON (Tx v i o w l) = - object - [ "version" .= v - , "inputs" .= i - , "outputs" .= o - , "witnessdata" .= fmap (fmap encodeHex) w - , "locktime" .= l - ] - toEncoding (Tx v i o w l) = - pairs - ( "version" .= v - <> "inputs" .= i - <> "outputs" .= o - <> "witnessdata" .= fmap (fmap encodeHex) w - <> "locktime" .= l - ) - - -- | Data type representing a transaction input. data TxIn = TxIn { prevOutput :: !OutPoint @@ -351,30 +303,6 @@ instance Serialize TxIn where put = serialize -instance FromJSON TxIn where - parseJSON = - withObject "TxIn" $ \o -> - TxIn - <$> o .: "prevoutput" - <*> (maybe mzero return . decodeHex =<< o .: "inputscript") - <*> o .: "sequence" - - -instance ToJSON TxIn where - toJSON (TxIn o s q) = - object - [ "prevoutput" .= o - , "inputscript" .= encodeHex s - , "sequence" .= q - ] - toEncoding (TxIn o s q) = - pairs - ( "prevoutput" .= o - <> "inputscript" .= encodeHex s - <> "sequence" .= q - ) - - -- | Data type representing a transaction output. data TxOut = TxOut { outValue :: !Word64 @@ -408,21 +336,6 @@ instance Serialize TxOut where get = deserialize -instance FromJSON TxOut where - parseJSON = - withObject "TxOut" $ \o -> - TxOut - <$> o .: "value" - <*> (maybe mzero return . decodeHex =<< o .: "outputscript") - - -instance ToJSON TxOut where - toJSON (TxOut o s) = - object ["value" .= o, "outputscript" .= encodeHex s] - toEncoding (TxOut o s) = - pairs ("value" .= o <> "outputscript" .= encodeHex s) - - -- | The 'OutPoint' refers to a transaction output being spent. data OutPoint = OutPoint { outPointHash :: !TxHash @@ -450,17 +363,6 @@ instance Serialize OutPoint where get = deserialize -instance FromJSON OutPoint where - parseJSON = - withObject "OutPoint" $ \o -> - OutPoint <$> o .: "txid" <*> o .: "index" - - -instance ToJSON OutPoint where - toJSON (OutPoint h i) = object ["txid" .= h, "index" .= i] - toEncoding (OutPoint h i) = pairs ("txid" .= h <> "index" .= i) - - -- | Outpoint used in coinbase transactions. nullOutPoint :: OutPoint nullOutPoint = diff --git a/src/Bitcoin/Transaction/Partial.hs b/src/Bitcoin/Transaction/Partial.hs index b11057e4..1c438564 100644 --- a/src/Bitcoin/Transaction/Partial.hs +++ b/src/Bitcoin/Transaction/Partial.hs @@ -34,25 +34,6 @@ module Bitcoin.Transaction.Partial ( signPSBT, ) where -import Control.Applicative ((<|>)) -import Control.DeepSeq -import Control.Monad (foldM, guard, replicateM, void) -import Data.ByteString (ByteString) -import qualified Data.ByteString as B -import Data.Bytes.Get (runGetS) -import Data.Bytes.Put (runPutS) -import Data.Bytes.Serial (Serial (..)) -import Data.Either (fromRight) -import Data.HashMap.Strict (HashMap) -import qualified Data.HashMap.Strict as HM -import qualified Data.HashMap.Strict as HashMap -import Data.Hashable (Hashable) -import Data.List (foldl') -import Data.Maybe (fromMaybe, isJust) -import Data.Serialize (Get, Put, Serialize) -import qualified Data.Serialize as S -import GHC.Generics (Generic) -import GHC.Word (Word32, Word8) import Bitcoin.Address (Address (..), pubKeyAddr) import Bitcoin.Crypto (SecKey, derivePubKey) import Bitcoin.Data (Network) @@ -106,6 +87,25 @@ import Bitcoin.Transaction.Common ( ) import Bitcoin.Transaction.Segwit (isSegwit) import Bitcoin.Util (eitherToMaybe) +import Control.Applicative ((<|>)) +import Control.DeepSeq +import Control.Monad (foldM, guard, replicateM, void) +import Data.ByteString (ByteString) +import qualified Data.ByteString as B +import Data.Bytes.Get (runGetS) +import Data.Bytes.Put (runPutS) +import Data.Bytes.Serial (Serial (..)) +import Data.Either (fromRight) +import Data.HashMap.Strict (HashMap) +import qualified Data.HashMap.Strict as HM +import qualified Data.HashMap.Strict as HashMap +import Data.Hashable (Hashable) +import Data.List (foldl') +import Data.Maybe (fromMaybe, isJust) +import Data.Serialize (Get, Put, Serialize) +import qualified Data.Serialize as S +import GHC.Generics (Generic) +import GHC.Word (Word32, Word8) -- | PSBT data type as specified in @@ -202,8 +202,6 @@ merge _ _ = Nothing -- | A version of 'merge' for a collection of PSBTs. --- --- @since 0.21.0 mergeMany :: [PartiallySignedTransaction] -> Maybe PartiallySignedTransaction mergeMany (psbt : psbts) = foldM merge psbt psbts mergeMany _ = Nothing @@ -256,8 +254,6 @@ mergeOutput a b = -- | A abstraction which covers varying key configurations. Use the 'Semigroup' -- instance to create signers for sets of keys: `signerA <> signerB` can sign -- anything for which `signerA` or `signerB` could sign. --- --- @since 0.21@ newtype PsbtSigner = PsbtSigner { unPsbtSigner :: PubKeyI -> @@ -277,15 +273,11 @@ instance Monoid PsbtSigner where -- | Fetch the secret key for the given 'PubKeyI' if possible. --- --- @since 0.21@ getSignerKey :: PsbtSigner -> PubKeyI -> Maybe (Fingerprint, DerivPath) -> Maybe SecKey getSignerKey = unPsbtSigner -- | This signer can sign for one key. --- --- @since 0.21@ secKeySigner :: SecKey -> PsbtSigner secKeySigner theSecKey = PsbtSigner signer where @@ -295,8 +287,6 @@ secKeySigner theSecKey = PsbtSigner signer -- | This signer can sign with any child key, provided that derivation information is present. --- --- @since 0.21@ xPrvSigner :: XPrvKey -> -- | Origin data, if the input key is explicitly a child key @@ -336,8 +326,6 @@ xPrvSigner xprv origin = PsbtSigner signer -- | Update a PSBT with signatures when possible. This function uses -- 'inputHDKeypaths' in order to calculate secret keys. --- --- @since 0.21@ signPSBT :: Network -> PsbtSigner -> diff --git a/src/Bitcoin/Transaction/Segwit.hs b/src/Bitcoin/Transaction/Segwit.hs index edec4535..76aefb8b 100644 --- a/src/Bitcoin/Transaction/Segwit.hs +++ b/src/Bitcoin/Transaction/Segwit.hs @@ -23,19 +23,17 @@ module Bitcoin.Transaction.Segwit ( toWitnessStack, ) where -import Data.ByteString (ByteString) -import Data.Bytes.Get -import Data.Bytes.Put -import Data.Bytes.Serial import Bitcoin.Data import Bitcoin.Keys.Common import Bitcoin.Script import Bitcoin.Transaction.Common +import Data.ByteString (ByteString) +import Data.Bytes.Get +import Data.Bytes.Put +import Data.Bytes.Serial -- | Test if a 'ScriptOutput' is P2WPKH or P2WSH --- --- @since 0.11.0.0 isSegwit :: ScriptOutput -> Bool isSegwit = \case PayWitnessPKHash{} -> True @@ -44,8 +42,6 @@ isSegwit = \case -- | High level represenation of a (v0) witness program --- --- @since 0.11.0.0 data WitnessProgram = P2WPKH WitnessProgramPKH | P2WSH WitnessProgramSH @@ -54,8 +50,6 @@ data WitnessProgram -- | Encode a witness program --- --- @since 0.11.0.0 toWitnessStack :: WitnessProgram -> WitnessStack toWitnessStack = \case P2WPKH (WitnessProgramPKH sig key) -> [encodeTxSig sig, runPutS (serialize key)] @@ -64,8 +58,6 @@ toWitnessStack = \case -- | High level representation of a P2WPKH witness --- --- @since 0.11.0.0 data WitnessProgramPKH = WitnessProgramPKH { witnessSignature :: !TxSignature , witnessPubKey :: !PubKeyI @@ -74,8 +66,6 @@ data WitnessProgramPKH = WitnessProgramPKH -- | High-level representation of a P2WSH witness --- --- @since 0.11.0.0 data WitnessProgramSH = WitnessProgramSH { witnessScriptHashStack :: ![ByteString] , witnessScriptHashScript :: !Script @@ -84,8 +74,6 @@ data WitnessProgramSH = WitnessProgramSH -- | Calculate the witness program from the transaction data --- --- @since 0.11.0.0 viewWitnessProgram :: Network -> ScriptOutput -> WitnessStack -> Either String WitnessProgram viewWitnessProgram net so witness = case so of @@ -102,8 +90,6 @@ viewWitnessProgram net so witness = case so of -- | Analyze the witness, trying to match it with standard input structures --- --- @since 0.11.0.0 decodeWitnessInput :: Network -> WitnessProgram -> @@ -124,8 +110,6 @@ decodeWitnessInput net = \case -- | Create the witness program for a standard input --- --- @since 0.11.0.0 calcWitnessProgram :: ScriptOutput -> ScriptInput -> Either String WitnessProgram calcWitnessProgram so si = case (so, si) of (PayWitnessPKHash{}, RegularInput (SpendPKHash sig pk)) -> p2wpkh sig pk @@ -139,8 +123,6 @@ calcWitnessProgram so si = case (so, si) of -- | Create the witness stack required to spend a standard P2WSH input --- --- @since 0.11.0.0 simpleInputStack :: SimpleInput -> [ByteString] simpleInputStack = \case SpendPK sig -> [f sig] diff --git a/src/Bitcoin/Transaction/Taproot.hs b/src/Bitcoin/Transaction/Taproot.hs index 64db6158..594d1bae 100644 --- a/src/Bitcoin/Transaction/Taproot.hs +++ b/src/Bitcoin/Transaction/Taproot.hs @@ -25,6 +25,12 @@ module Bitcoin.Transaction.Taproot ( verifyScriptPathData, ) where +import Bitcoin.Crypto (PubKey, initTaggedHash, tweak, tweakAddPubKey) +import Bitcoin.Keys.Common (PubKeyI (PubKeyI), pubKeyPoint) +import Bitcoin.Script.Common (Script) +import Bitcoin.Script.Standard (ScriptOutput (PayWitness)) +import Bitcoin.Transaction.Common (WitnessStack) +import Bitcoin.Util (decodeHex, eitherToMaybe, encodeHex) import Control.Applicative (many) import Control.Monad ((<=<)) import Crypto.Hash ( @@ -35,7 +41,6 @@ import Crypto.Hash ( hashUpdate, hashUpdates, ) -import Data.Aeson (FromJSON (parseJSON), ToJSON (toJSON), withText) import Data.Binary (Binary (..)) import Data.Bits ((.&.), (.|.)) import Data.Bool (bool) @@ -50,19 +55,11 @@ import Data.Foldable (foldl') import Data.Maybe (fromMaybe, mapMaybe) import Data.Serialize (Serialize, get, getByteString, getWord8, put) import Data.Word (Word8) -import Bitcoin.Crypto (PubKey, initTaggedHash, tweak, tweakAddPubKey) -import Bitcoin.Keys.Common (PubKeyI (PubKeyI), pubKeyPoint) -import Bitcoin.Script.Common (Script) -import Bitcoin.Script.Standard (ScriptOutput (PayWitness)) -import Bitcoin.Transaction.Common (WitnessStack) -import Bitcoin.Util (decodeHex, eitherToMaybe, encodeHex) -- | An x-only pubkey corresponds to the keys @(x,y)@ and @(x, -y)@. The --equality test only checks the x-coordinate. An x-only pubkey serializes to 32 --bytes. --- --- @since 0.21.0 newtype XOnlyPubKey = XOnlyPubKey {xOnlyPubKey :: PubKey} deriving (Show) @@ -95,28 +92,12 @@ instance Binary XOnlyPubKey where get = deserialize --- | Hex encoding -instance FromJSON XOnlyPubKey where - parseJSON = - withText "XOnlyPubKey" $ - either fail pure - . (runGetS deserialize <=< maybe (Left "Unable to decode hex") Right . decodeHex) - - --- | Hex encoding -instance ToJSON XOnlyPubKey where - toJSON = toJSON . encodeHex . runPutS . serialize - - --- | @since 0.21.0 type TapLeafVersion = Word8 -- | Merklized Abstract Syntax Tree. This type can represent trees where only a --subset of the leaves are known. Note that the tree is invariant under swapping --branches at an internal node. --- --- @since 0.21.0 data MAST = MASTBranch MAST MAST | MASTLeaf TapLeafVersion Script @@ -126,8 +107,6 @@ data MAST -- | Get the inclusion proofs for the leaves in the tree. The proof is ordered --leaf-to-root. --- --- @since 0.21.0 getMerkleProofs :: MAST -> [(TapLeafVersion, Script, [Digest SHA256])] getMerkleProofs = getProofs mempty where @@ -142,8 +121,6 @@ getMerkleProofs = getProofs mempty -- | Calculate the root hash for this tree. --- --- @since 0.21.0 mastCommitment :: MAST -> Digest SHA256 mastCommitment = \case MASTBranch leftBranch rightBranch -> @@ -176,8 +153,6 @@ leafHash leafVersion leafScript = -- | Representation of a full taproot output. --- --- @since 0.21.0 data TaprootOutput = TaprootOutput { taprootInternalKey :: PubKey , taprootMAST :: Maybe MAST @@ -185,7 +160,6 @@ data TaprootOutput = TaprootOutput deriving (Show) --- | @since 0.21.0 taprootOutputKey :: TaprootOutput -> PubKey taprootOutputKey TaprootOutput{taprootInternalKey, taprootMAST} = fromMaybe keyFail $ tweak commitment >>= tweakAddPubKey taprootInternalKey @@ -206,15 +180,11 @@ taprootCommitment internalKey merkleRoot = -- | Generate the output script for a taproot output --- --- @since 0.21.0 taprootScriptOutput :: TaprootOutput -> ScriptOutput taprootScriptOutput = PayWitness 0x01 . runPutS . serialize . XOnlyPubKey . taprootOutputKey -- | Comprehension of taproot witness data --- --- @since 0.21.0 data TaprootWitness = -- | Signature KeyPathSpend ByteString @@ -222,7 +192,6 @@ data TaprootWitness deriving (Eq, Show) --- | @since 0.21.0 data ScriptPathData = ScriptPathData { scriptPathAnnex :: Maybe ByteString , scriptPathStack :: [ByteString] @@ -237,8 +206,6 @@ data ScriptPathData = ScriptPathData -- | Try to interpret a 'WitnessStack' as taproot witness data. --- --- @since 0.21.0 viewTaprootWitness :: WitnessStack -> Maybe TaprootWitness viewTaprootWitness witnessStack = case reverse witnessStack of [sig] -> Just $ KeyPathSpend sig @@ -271,8 +238,6 @@ viewTaprootWitness witnessStack = case reverse witnessStack of -- | Transform the high-level representation of taproot witness data into a witness stack --- --- @since 0.21.0 encodeTaprootWitness :: TaprootWitness -> WitnessStack encodeTaprootWitness = \case KeyPathSpend signature -> pure signature @@ -291,8 +256,6 @@ encodeTaprootWitness = \case -- | Verify that the script path spend is valid, except for script execution. --- --- @since 0.21.0 verifyScriptPathData :: -- | Output key PubKey -> diff --git a/src/Bitcoin/Util.hs b/src/Bitcoin/Util.hs index fc884f48..2f6d95a3 100644 --- a/src/Bitcoin/Util.hs +++ b/src/Bitcoin/Util.hs @@ -21,7 +21,6 @@ module Bitcoin.Util ( -- * Maybe & Either Helpers eitherToMaybe, maybeToEither, - liftEither, liftMaybe, -- * Other Helpers @@ -34,10 +33,6 @@ module Bitcoin.Util ( snd3, lst3, - -- * JSON Utilities - dropFieldLabel, - dropSumLabels, - -- * Serialization Helpers putList, getList, @@ -58,13 +53,7 @@ module Bitcoin.Util ( ) where import Control.Monad -import Control.Monad.Except (ExceptT (..), liftEither) -import Data.Aeson.Types ( - Options (..), - SumEncoding (..), - defaultOptions, - defaultTaggedObject, - ) +import Control.Monad.Trans.Except (ExceptT (..)) import Data.Bits import Data.ByteString (ByteString) import qualified Data.ByteString as BS @@ -160,7 +149,7 @@ maybeToEither err = maybe (Left err) Right -- | Lift a 'Maybe' computation into the 'ExceptT' monad. liftMaybe :: Monad m => b -> Maybe a -> ExceptT b m a -liftMaybe err = liftEither . maybeToEither err +liftMaybe err = ExceptT . pure . maybeToEither err -- Various helpers @@ -217,26 +206,6 @@ lst3 :: (a, b, c) -> c lst3 (_, _, c) = c --- | Field label goes lowercase and first @n@ characters get removed. -dropFieldLabel :: Int -> Options -dropFieldLabel n = - defaultOptions - { fieldLabelModifier = map toLower . drop n - } - - --- | Transformation from 'dropFieldLabel' is applied with argument @f@, plus --- constructor tags are lowercased and first @c@ characters removed. @tag@ is --- used as the name of the object field name that will hold the transformed --- constructor tag as its value. -dropSumLabels :: Int -> Int -> String -> Options -dropSumLabels c f tag = - (dropFieldLabel f) - { constructorTagModifier = map toLower . drop c - , sumEncoding = defaultTaggedObject{tagFieldName = tag} - } - - -- | Convert from one power-of-two base to another, as long as it fits in a -- 'Word'. convertBits :: Bool -> Int -> Int -> [Word] -> ([Word], Bool) diff --git a/src/Bitcoin/Util/Arbitrary/Transaction.hs b/src/Bitcoin/Util/Arbitrary/Transaction.hs index 63e64355..e4d0a7bd 100644 --- a/src/Bitcoin/Util/Arbitrary/Transaction.hs +++ b/src/Bitcoin/Util/Arbitrary/Transaction.hs @@ -3,11 +3,6 @@ -- Portability : POSIX module Bitcoin.Util.Arbitrary.Transaction where -import Control.Monad -import qualified Data.ByteString as BS -import Data.Either (fromRight) -import Data.List (nub, nubBy, permutations) -import Data.Word (Word64) import Bitcoin.Address import Bitcoin.Constants import Bitcoin.Data @@ -18,6 +13,11 @@ import Bitcoin.Util.Arbitrary.Crypto import Bitcoin.Util.Arbitrary.Keys import Bitcoin.Util.Arbitrary.Script import Bitcoin.Util.Arbitrary.Util +import Control.Monad +import qualified Data.ByteString as BS +import Data.Either (fromRight) +import Data.List (nub, nubBy, permutations) +import Data.Word (Word64) import Test.QuickCheck @@ -26,10 +26,6 @@ newtype TestCoin = TestCoin {getTestCoin :: Word64} deriving (Eq, Show) -instance Coin TestCoin where - coinValue = getTestCoin - - -- | Arbitrary transaction hash (for non-existent transaction). arbitraryTxHash :: Gen TxHash arbitraryTxHash = TxHash <$> arbitraryHash256 diff --git a/src/Bitcoin/Util/Arbitrary/Util.hs b/src/Bitcoin/Util/Arbitrary/Util.hs index 663c2679..60e95f4e 100644 --- a/src/Bitcoin/Util/Arbitrary/Util.hs +++ b/src/Bitcoin/Util/Arbitrary/Util.hs @@ -15,22 +15,17 @@ module Bitcoin.Util.Arbitrary.Util ( arbitraryNetwork, arbitraryUTCTime, SerialBox (..), - JsonBox (..), - NetBox (..), ReadBox (..), testIdentity, testSerial, testRead, - testJson, - testNetJson, arbitraryNetData, genNetData, ) where +import Bitcoin.Constants +import Bitcoin.Data import Control.Monad (forM_, (<=<)) -import qualified Data.Aeson as A -import qualified Data.Aeson.Encoding as A -import qualified Data.Aeson.Types as A import Data.ByteString (ByteString, pack) import Data.ByteString.Lazy (fromStrict, toStrict) import qualified Data.ByteString.Short as BSS @@ -43,8 +38,6 @@ import Data.Time.Clock (UTCTime (..)) import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import qualified Data.Typeable as T import Data.Word (Word32) -import Bitcoin.Constants -import Bitcoin.Data import Test.Hspec (Spec, describe, shouldBe, shouldSatisfy) import Test.Hspec.QuickCheck (prop) import Test.QuickCheck @@ -115,37 +108,24 @@ data ReadBox ReadBox (Gen a) -data JsonBox - = forall a. - (Show a, Eq a, T.Typeable a, A.ToJSON a, A.FromJSON a) => - JsonBox (Gen a) - - -data NetBox - = forall a. - (Show a, Eq a, T.Typeable a) => - NetBox - ( Network -> a -> A.Value - , Network -> a -> A.Encoding - , Network -> A.Value -> A.Parser a - , Gen (Network, a) - ) +-- data NetBox +-- = forall a. +-- (Show a, Eq a, T.Typeable a) => +-- NetBox +-- ( Network -> a -> A.Value +-- , Network -> a -> A.Encoding +-- , Network -> A.Value -> A.Parser a +-- , Gen (Network, a) +-- ) - -testIdentity :: [SerialBox] -> [ReadBox] -> [JsonBox] -> [NetBox] -> Spec -testIdentity serialVals readVals jsonVals netVals = do +testIdentity :: [SerialBox] -> [ReadBox] -> Spec +testIdentity serialVals readVals = do describe "Binary Encoding" $ forM_ serialVals $ \(SerialBox g) -> testSerial g describe "Read/Show Encoding" $ forM_ readVals $ \(ReadBox g) -> testRead g - describe "Data.Aeson Encoding" $ - forM_ jsonVals $ - \(JsonBox g) -> testJson g - describe "Data.Aeson Encoding with Network" $ - forM_ netVals $ - \(NetBox (j, e, p, g)) -> testNetJson j e p g -- | Generate binary identity tests @@ -177,48 +157,6 @@ testRead gen = proxy = const Proxy --- | Generate Data.Aeson identity tests -testJson :: - (Eq a, Show a, T.Typeable a, A.ToJSON a, A.FromJSON a) => Gen a -> Spec -testJson gen = do - prop ("Data.Aeson toJSON/fromJSON identity for " <> name) $ - forAll gen (`shouldSatisfy` jsonID) - prop ("Data.Aeson toEncoding/fromJSON identity for " <> name) $ - forAll gen (`shouldSatisfy` encodingID) - where - name = show $ T.typeRep $ proxy gen - proxy :: Gen a -> Proxy a - proxy = const Proxy - jsonID x = (A.fromJSON . A.toJSON) (toMap x) == A.Success (toMap x) - encodingID x = - (A.decode . A.encodingToLazyByteString . A.toEncoding) (toMap x) - == Just (toMap x) - - --- | Generate Data.Aeson identity tests for type that need the @Network@ -testNetJson :: - (Eq a, Show a, T.Typeable a) => - (Network -> a -> A.Value) -> - (Network -> a -> A.Encoding) -> - (Network -> A.Value -> A.Parser a) -> - Gen (Network, a) -> - Spec -testNetJson j e p g = do - prop ("Data.Aeson toJSON/fromJSON identity (with network) for " <> name) $ - forAll g $ - \(net, x) -> dec net (encVal net x) `shouldBe` Just x - prop ("Data.Aeson toEncoding/fromJSON identity (with network) for " <> name) $ - forAll g $ - \(net, x) -> dec net (encEnc net x) `shouldBe` Just x - where - encVal net = A.encode . toMap . j net - encEnc net = A.encodingToLazyByteString . toMapE . e net - dec net = A.parseMaybe (p net) . fromMap <=< A.decode - name = show $ T.typeRep $ proxy j - proxy :: (Network -> a -> A.Value) -> Proxy a - proxy = const Proxy - - arbitraryNetData :: Arbitrary a => Gen (Network, a) arbitraryNetData = do net <- arbitraryNetwork @@ -237,9 +175,5 @@ toMap :: a -> Map.Map String a toMap = Map.singleton "object" -toMapE :: A.Encoding -> A.Encoding -toMapE = A.pairs . A.pair "object" - - fromMap :: Map.Map String a -> a fromMap = (Map.! "object") diff --git a/stack.yaml b/stack.yaml index f3a4011d..5f4ead64 100644 --- a/stack.yaml +++ b/stack.yaml @@ -6,3 +6,4 @@ nix: - pkg-config extra-deps: - fourmolu-0.8.2.0 + - libsecp256k1-0.1.0 diff --git a/stack.yaml.lock b/stack.yaml.lock index eefaa121..2c315e64 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -11,6 +11,13 @@ packages: sha256: e467a3bce53e6bbb71414a368369095eee13e423d093a5aff2cd128317362c3e original: hackage: fourmolu-0.8.2.0 +- completed: + hackage: libsecp256k1-0.1.0@sha256:c8de65c640e2e36b14947db00366228d550881640f5e61f496aeb2249966039c,1898 + pantry-tree: + size: 901 + sha256: 9713733dbf509b8af64449ea9b4b3d1ee518cb1e7e61c03a8a9297fa29c3b274 + original: + hackage: libsecp256k1-0.1.0 snapshots: - completed: size: 619399