packages feed

bitcoin-payment-channel 0.2.1.0 → 0.2.2.0

raw patch · 11 files changed

+94/−52 lines, 11 files

Files

bitcoin-payment-channel.cabal view
@@ -1,5 +1,5 @@ name:                 bitcoin-payment-channel-version:              0.2.1.0+version:              0.2.2.0 synopsis:             Library for working with Bitcoin payment channels description:     A Bitcoin payment channel allows secure and instant transfer of bitcoins from one@@ -37,6 +37,7 @@    other-modules:                         Data.Bitcoin.PaymentChannel.Internal.Error+                        Data.Bitcoin.PaymentChannel.Internal.BitcoinAmount,                         Data.Bitcoin.PaymentChannel.Internal.Payment,                         Data.Bitcoin.PaymentChannel.Internal.Refund,                         Data.Bitcoin.PaymentChannel.Internal.Script,@@ -46,6 +47,7 @@                         Data.Bitcoin.PaymentChannel.Internal.Serialization,                         Data.Bitcoin.PaymentChannel.Internal.Util,                         Data.Bitcoin.PaymentChannel.Internal.Version+    ghc-options:          -W 
+ src/Data/Bitcoin/PaymentChannel/Internal/BitcoinAmount.hs view
@@ -0,0 +1,60 @@+module Data.Bitcoin.PaymentChannel.Internal.BitcoinAmount where++import qualified Data.Serialize     as Ser+import qualified Data.Serialize.Put as SerPut+import qualified Data.Serialize.Get as SerGet+import qualified Data.Binary        as Bin+import qualified Data.Binary.Put    as BinPut+import qualified Data.Binary.Get    as BinGet+import           Data.Word+++-- |Represents a bitcoin amount as number of satoshis.+--  1 satoshi = 1e-8 bitcoin.+--  Only natural numbers (>= 0) can be represented ('fromInteger' caps to a 'Word64').+--  It is thus not possible to construct a negative BitcoinAmount which, when added to+--  another BitcoinAmount, subtracts from its value. So we avoid the problem of being+--  able to invert subtraction/addition by supplying a negative value as one of the+--  arguments.+newtype BitcoinAmount = BitcoinAmount Integer+    deriving (Eq, Ord)+instance Show BitcoinAmount where+    show amount = show (toInteger amount) ++ " satoshi"++instance Num BitcoinAmount where+    -- We leave multiplication of two money amounts as undefined+    (BitcoinAmount _)  * (BitcoinAmount _)  = undefined+    (BitcoinAmount a1) + (BitcoinAmount a2) = BitcoinAmount (fromIntegral . capToWord64 $ a1+a2)+    (BitcoinAmount a1) - (BitcoinAmount a2) = BitcoinAmount (fromIntegral . capToWord64 $ a1-a2)+    abs = id    -- Always positive+    signum (BitcoinAmount 0) = BitcoinAmount 0+    signum (BitcoinAmount _) = BitcoinAmount 1+    fromInteger = BitcoinAmount . fromIntegral . capToWord64++instance Enum BitcoinAmount where+    toEnum = BitcoinAmount . fromIntegral . capToWord64 . fromIntegral+    fromEnum (BitcoinAmount amount) = fromIntegral amount++instance Real BitcoinAmount where+    toRational (BitcoinAmount amount) = toRational amount++instance Integral BitcoinAmount where+    toInteger (BitcoinAmount int) = int+    -- Dividing one money amounts by another doesn't make sense either+    quotRem (BitcoinAmount _) (BitcoinAmount _) = undefined++-- | Convert to 'Word64', with zero as floor, (maxBound :: Word64) as ceiling+capToWord64 :: Integer -> Word64+capToWord64 i = fromIntegral $+    max 0 cappedValue+        where+            cappedValue = min i $ fromIntegral (maxBound :: Word64)++instance Bin.Binary BitcoinAmount where+    put = BinPut.putWord64le . fromIntegral . toInteger+    get = BitcoinAmount . fromIntegral <$> BinGet.getWord64le++instance Ser.Serialize BitcoinAmount where+    put = SerPut.putWord64le . fromIntegral . toInteger+    get = BitcoinAmount . fromIntegral <$> SerGet.getWord64le+
src/Data/Bitcoin/PaymentChannel/Internal/Error.hs view
@@ -1,6 +1,6 @@ module Data.Bitcoin.PaymentChannel.Internal.Error where -import Data.Bitcoin.PaymentChannel.Internal.Util (BitcoinAmount)+import Data.Bitcoin.PaymentChannel.Internal.Types (BitcoinAmount)  data PayChanError =     BadSignature |
src/Data/Bitcoin/PaymentChannel/Internal/Payment.hs view
@@ -43,7 +43,7 @@ getPaymentTxForSigning st@(CPaymentChannelState _ fti     (CPaymentTxConfig sendAddr) chanValLeft _) newValueLeft =         paymentTxAddOutput senderOut $ buildEmptyPaymentTx fti-            where senderOut = HT.TxOut (toWord64 newValueLeft) (addressToScriptPubKeyBS sendAddr)+            where senderOut = HT.TxOut (fromIntegral . toInteger $ newValueLeft) (addressToScriptPubKeyBS sendAddr)  getPaymentTxHashForSigning ::     PaymentChannelState
src/Data/Bitcoin/PaymentChannel/Internal/Refund.hs view
@@ -14,13 +14,15 @@ getUnsignedRefundTx st txFee = -- @CPaymentChannelState =     let         (baseTx,_) = getPaymentTxForSigning st 0 --create empty payment tx, which redeems funding tx-        refundOut = HT.TxOut (toWord64 $ pcsChannelTotalValue st - txFee) (pcsClientChange st)+        refundOut = HT.TxOut+                (fromIntegral . toInteger $ pcsChannelTotalValue st - txFee)+                (pcsClientChangeScriptPubKey st)         txInput0 = head $ HT.txIn baseTx     in         baseTx {             HT.txOut = [refundOut],-            -- lockTime of refund tx must be equal to or greater than lockTime-            -- in channel redeemScript+            -- lockTime of refund tx must be greater than or equal to the lockTime+            -- in the channel redeemScript             HT.txLockTime = toWord32 (pcsLockTime st),             -- if the sequence field equals maxBound (0xffffffff),             -- lockTime features are disabled, so we set it to that minus one
src/Data/Bitcoin/PaymentChannel/Internal/Serialization.hs view
@@ -6,7 +6,7 @@  import           Data.Bitcoin.PaymentChannel.Internal.Types import           Data.Bitcoin.PaymentChannel.Internal.Util-                            (BitcoinAmount(..), toWord64, deserEither, toHexString,+                            (deserEither, toHexString,                              parseBitcoinLocktime, BitcoinLockTime(..), toWord32)  import           Data.Aeson (Value(Number), FromJSON(..), ToJSON(..),@@ -50,7 +50,7 @@  instance ToJSON BitcoinAmount where     toJSON amt = Number $ scientific-        (fromIntegral $ toWord64 amt) 0+        (fromIntegral $ toInteger amt) 0  instance FromJSON BitcoinAmount where     parseJSON = withScientific "BitcoinAmount" $@@ -113,8 +113,8 @@      -- Needed to convert from Scientific instance Bounded BitcoinAmount where-    minBound = CMoneyAmount 0-    maxBound = CMoneyAmount $ round $ 21e6 * 1e8+    minBound = BitcoinAmount 0+    maxBound = BitcoinAmount $ round $ 21e6 * 1e8   --- Util@@ -138,7 +138,7 @@ parseJSONInt :: Scientific -> Parser Integer parseJSONInt s =     case toBoundedInteger s of-        Just (CMoneyAmount i) -> return i+        Just (BitcoinAmount i) -> return i         Nothing -> fail $ "failed to decode JSON number to integer. data: " ++ show s  parseJSONWord :: Scientific -> Parser Word64
src/Data/Bitcoin/PaymentChannel/Internal/Settlement.hs view
@@ -24,7 +24,7 @@             (baseTx,_) = getPaymentTxForSigning st senderVal             adjTx = if sigHash == HS.SigNone True then removeOutputs baseTx else baseTx             receiverAmount = channelTotalValue - senderVal - txFee -- may be less than zero-            recvOut = HT.TxOut (toWord64 receiverAmount) (addressToScriptPubKeyBS recvAddr)+            recvOut = HT.TxOut (fromIntegral . toInteger $ receiverAmount) (addressToScriptPubKeyBS recvAddr)         in             paymentTxAddOutput recvOut adjTx getSettlementTxForSigning _ _ _ = error "no payment sig available"
src/Data/Bitcoin/PaymentChannel/Internal/State.hs view
@@ -4,7 +4,7 @@  import Data.Bitcoin.PaymentChannel.Internal.Types import Data.Bitcoin.PaymentChannel.Internal.Error-import Data.Bitcoin.PaymentChannel.Internal.Util  (addressToScriptPubKeyBS, BitcoinAmount)+import Data.Bitcoin.PaymentChannel.Internal.Util  (addressToScriptPubKeyBS)  import qualified Network.Haskoin.Transaction as HT import qualified Network.Haskoin.Crypto as HC@@ -17,7 +17,7 @@ pcsServerPubKey = cpReceiverPubKey . pcsParameters pcsExpirationDate = cpLockTime . pcsParameters pcsClientChangeAddress = ptcSenderChangeAddress . pcsPaymentConfig-pcsClientChange = addressToScriptPubKeyBS . pcsClientChangeAddress+pcsClientChangeScriptPubKey = addressToScriptPubKeyBS . pcsClientChangeAddress pcsLockTime = cpLockTime . pcsParameters  pcsChannelID :: PaymentChannelState -> HT.OutPoint
src/Data/Bitcoin/PaymentChannel/Internal/Types.hs view
@@ -1,19 +1,23 @@ -- {-# LANGUAGE DeriveDataTypeable #-} -module Data.Bitcoin.PaymentChannel.Internal.Types where+module Data.Bitcoin.PaymentChannel.Internal.Types+(+    module Data.Bitcoin.PaymentChannel.Internal.Types+  , module Data.Bitcoin.PaymentChannel.Internal.BitcoinAmount+) +where+ import Data.Bitcoin.PaymentChannel.Internal.Util import Data.Bitcoin.PaymentChannel.Internal.Version+import Data.Bitcoin.PaymentChannel.Internal.BitcoinAmount  import qualified  Network.Haskoin.Transaction as HT import qualified  Network.Haskoin.Crypto as HC import qualified  Network.Haskoin.Script as HS-import qualified Data.ByteString as B-import Data.Word (Word32, Word64, Word8)-import qualified  Data.Binary as Bin-import qualified  Data.Binary.Put as BinPut-import qualified  Data.Binary.Get as BinGet import            Data.Typeable+import            Data.Word+  dUST_LIMIT = 700 :: BitcoinAmount mIN_CHANNEL_SIZE = dUST_LIMIT * 2
src/Data/Bitcoin/PaymentChannel/Internal/Util.hs view
@@ -4,7 +4,7 @@ module Data.Bitcoin.PaymentChannel.Internal.Util where  import Data.String (fromString)-import qualified Data.Serialize as Ser (Serialize, encode, get, put)+import qualified Data.Serialize as Ser import qualified Data.Serialize.Put as SerPut import qualified Data.Serialize.Get as SerGet import qualified Data.Binary as Bin@@ -44,32 +44,6 @@         (bs,e) ->             if B.length e /= 0 then B.empty else bs ---- |Represents a bitcoin amount as number of satoshis.---  1 satoshi = 1e-8 bitcoins.---  Integer operations will never over- or underflow with this type.---  Convert to a Word64 using 'toWord64', which caps the final amount.-newtype BitcoinAmount = CMoneyAmount Integer-    deriving (Eq, Ord, Num, Enum, Real, Integral)-instance Show BitcoinAmount where-    show ma = show (fromIntegral $ toWord64 ma) ++ " satoshi"---- | Convert to 'Word64', with zero as floor, UINT64_MAX as ceiling-toWord64 :: BitcoinAmount -> Word64-toWord64 (CMoneyAmount i) = fromIntegral $-    max 0 cappedValue-        where-            cappedValue = min i $ fromIntegral (maxBound :: Word64)--instance Bin.Binary BitcoinAmount where-    put = BinPut.putWord64le . toWord64-    get = CMoneyAmount . fromIntegral <$> BinGet.getWord64le--instance Ser.Serialize BitcoinAmount where-    put = SerPut.putWord64le . toWord64-    get = CMoneyAmount . fromIntegral <$> SerGet.getWord64le-- -- | Converts a pay-to-pubkey-hash address string to Script. -- | Eg. \"1PDGytNA7EJ5XrJdTGKv11VAUFxKnsfwke\" into -- | \"Script [OP_DUP, OP_HASH160, OP_PUSHDATA f3a5194fbf4b3556838e0f773b613a876737a2c6,@@ -122,7 +96,7 @@ replaceScriptInput scriptIn (HT.Tx v (txIn:_) txOut lt)  =     HT.Tx v [newTxIn] txOut lt         where newTxIn = txIn { HT.scriptInput = scriptIn }-replaceScriptInput scriptIn (HT.Tx _ [] _ _) =+replaceScriptInput _ (HT.Tx _ [] _ _) =     error "cannot replace scriptInput without any inputs"  removeOutputs :: HT.Tx -> HT.Tx
src/Data/Bitcoin/PaymentChannel/Types.hs view
@@ -21,7 +21,7 @@ PayChanError(..), PaymentChannelState, SendPubKey(..),RecvPubKey(..),IsPubKey(..),-BitcoinAmount, toWord64,+BitcoinAmount, BitcoinLockTime(..), fromDate, usesBlockHeight, @@ -34,15 +34,15 @@ where  import Data.Bitcoin.PaymentChannel.Internal.Types-    (PaymentChannelState(..), Payment(..)+    (BitcoinAmount(..),+     PaymentChannelState(..), Payment(..)     ,FundingTxInfo(..), ChannelParameters(..),     PaymentSignature(..), SendPubKey(..), RecvPubKey(..), IsPubKey(..),     dUST_LIMIT, mIN_CHANNEL_SIZE) import Data.Bitcoin.PaymentChannel.Internal.Serialization --     () import Data.Bitcoin.PaymentChannel.Internal.Util-    (BitcoinAmount(..), toWord64,-    BitcoinLockTime(..), fromDate, usesBlockHeight)+    (BitcoinLockTime(..), fromDate, usesBlockHeight) import qualified Data.Bitcoin.PaymentChannel.Internal.State as S import Data.Bitcoin.PaymentChannel.Internal.Error (PayChanError(..)) -- import Data.Bitcoin.PaymentChannel.Internal.Types ()