bitcoin-payment-channel-0.1.0.0: src/Data/Bitcoin/PaymentChannel/Internal/Payment.hs
module Data.Bitcoin.PaymentChannel.Internal.Payment where
import Data.Bitcoin.PaymentChannel.Internal.Types
import Data.Bitcoin.PaymentChannel.Internal.State
import Data.Bitcoin.PaymentChannel.Internal.Script
import Data.Bitcoin.PaymentChannel.Internal.Util
import Data.Bitcoin.PaymentChannel.Internal.Error
import qualified Network.Haskoin.Transaction as HT
import qualified Network.Haskoin.Internals as HI
import qualified Network.Haskoin.Crypto as HC
import qualified Network.Haskoin.Script as HS
import Data.Word (Word32, Word64, Word8)
import Data.Maybe (fromJust, isJust)
import qualified Data.ByteString as B
buildEmptyPaymentTx :: FundingTxInfo -> HT.Tx
buildEmptyPaymentTx (CFundingTxInfo hash idx _) =
HT.Tx 1 --version 1
-- Redeems payment channel output from blockchain Tx
[HT.TxIn
(HT.OutPoint hash idx)
B.empty
maxBound]
[]
0
paymentTxAddOutput :: HT.TxOut -> HT.Tx -> (HT.Tx, HS.SigHash)
paymentTxAddOutput addOut tx@(HT.Tx _ _ outs _)
| HT.outValue addOut >= dUST_LIMIT =
(tx { HT.txOut = outs ++ [addOut] }, HS.SigSingle True)
| otherwise =
(tx, HS.SigNone True)
getPaymentTxForSigning ::
PaymentChannelState
-> BitcoinAmount -- ^New sender value (newValueLeft)
-> (HT.Tx, HS.SigHash)
getPaymentTxForSigning st@(CPaymentChannelState _ fti
(CPaymentTxConfig sendChg _) chanValLeft _) newValueLeft =
paymentTxAddOutput senderOut $ buildEmptyPaymentTx fti
where senderOut = HT.TxOut (toWord64 newValueLeft) sendChg
getPaymentTxHashForSigning ::
PaymentChannelState
-> BitcoinAmount -- ^New sender value (newValueLeft)
-> (HC.Hash256, HS.SigHash) -- ^Hash of payment transaction with a single output paying to senderPK
getPaymentTxHashForSigning st@(CPaymentChannelState
cp@(CChannelParameters senderPK rcvrPK lt) _ _ _ _) newValueLeft =
(HS.txSigHash tx (getRedeemScript cp) 0 sigHash, sigHash)
where (tx,sigHash) = getPaymentTxForSigning st newValueLeft
verifyPayment ::
PaymentChannelState
-> Payment
-> (HC.Hash256 -> HC.PubKey -> HC.Signature -> Bool)
-> Bool
verifyPayment pcs
(CPayment newSenderVal (CPaymentSignature sig sigHash)) verifyFunc =
let (hash,_) = case sigHash of --SigHash in signature overrides newSenderVal
HS.SigSingle True -> getPaymentTxHashForSigning pcs newSenderVal
--sender has relinquished remaining channel value
HS.SigNone True -> getPaymentTxHashForSigning pcs 0
unknownSigHash -> (dummyHash256,sigHash) --will fail verification
in
verifyFunc hash (pcsClientPubKey pcs) sig
createPayment ::
PaymentChannelState
-> BitcoinAmount -- ^ newSenderVal
-> (HC.Hash256 -> HC.Signature) -- ^ signing function
-> Payment
createPayment pcs@(CPaymentChannelState _ _ _ currSenderVal _)
newSenderVal signFunc =
let
(hash,sigHash) = getPaymentTxHashForSigning pcs newSenderVal
sig = signFunc hash
pSig = CPaymentSignature sig sigHash
in
case sigHash of
HS.SigSingle _ -> CPayment newSenderVal pSig
--sender has reliquished the remaining channel value,
-- due to it being below the "dust" limit.
HS.SigNone _ -> CPayment 0 pSig
HS.SigAll _ -> error "BUG: unsupported SigHash"
HS.SigUnknown _ _ -> error "BUG: unsupported SigHash"