-
Notifications
You must be signed in to change notification settings - Fork 157
/
Tx.hs
129 lines (110 loc) · 4.15 KB
/
Tx.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Tx
( -- transaction
Tx(..)
, TxBody(..)
, TxOut(..)
, TxIn(..)
, TxId(..)
, txUpdate
, inputs
, outputs
, certs
, wdrls
, txfee
, ttl
, body
, witnessVKeySet
, witnessMSigMap
-- witness data
, WitVKey(..)
, MultiSignatureScript
, validateScript
, hashScript
, txwitsScript
, extractKeyHash
, extractScriptHash
)
where
import Keys (AnyKeyHash, undiscriminateKeyHash)
import Cardano.Binary (ToCBOR (toCBOR), encodeWord8)
import Cardano.Crypto.Hash (HashAlgorithm, hashWithSerialiser)
import Cardano.Crypto.DSIGN (DSIGNAlgorithm)
import Data.Word (Word8)
import qualified Data.Map.Strict as Map
import Data.Maybe (mapMaybe)
import Data.Set (Set)
import qualified Data.Set as Set
import TxData (Credential (..), MultiSig (..), ScriptHash (..), StakeCredential, Tx (..),
TxBody (..), TxId (..), TxIn (..), TxOut (..), WitVKey (..), body, certs,
inputs, outputs, ttl, txUpdate, txfee, wdrls, witKeyHash, witnessMSigMap,
witnessVKeySet)
-- | Typeclass for multis-signature script data types. Allows for script
-- validation and hashing.
class (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo, ToCBOR a) =>
MultiSignatureScript a hashAlgo dsignAlgo where
validateScript :: a -> Tx hashAlgo dsignAlgo -> Bool
hashScript :: a -> ScriptHash hashAlgo dsignAlgo
-- | Script evaluator for native multi-signature scheme. 'vhks' is the set of
-- key hashes that signed the transaction to be validated.
evalNativeMultiSigScript
:: MultiSig hashAlgo dsignAlgo
-> Set (AnyKeyHash hashAlgo dsignAlgo)
-> Bool
evalNativeMultiSigScript (RequireSignature hk) vhks = Set.member hk vhks
evalNativeMultiSigScript (RequireAllOf msigs) vhks =
all (`evalNativeMultiSigScript` vhks) msigs
evalNativeMultiSigScript (RequireAnyOf msigs) vhks =
any (`evalNativeMultiSigScript` vhks) msigs
evalNativeMultiSigScript (RequireMOf m msigs) vhks =
m <= sum [if evalNativeMultiSigScript msig vhks then 1 else 0 | msig <- msigs]
-- | Script validator for native multi-signature scheme.
validateNativeMultiSigScript
:: (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo)
=> MultiSig hashAlgo dsignAlgo
-> Tx hashAlgo dsignAlgo
-> Bool
validateNativeMultiSigScript msig tx =
evalNativeMultiSigScript msig vhks
where witsSet = _witnessVKeySet tx
vhks = Set.map witKeyHash witsSet
-- | Hashes native multi-signature script, appending the 'nativeMultiSigTag' in
-- front and then calling the script CBOR function.
hashNativeMultiSigScript
:: (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo)
=> MultiSig hashAlgo dsignAlgo
-> ScriptHash hashAlgo dsignAlgo
hashNativeMultiSigScript msig =
ScriptHash $ hashWithSerialiser (\x -> encodeWord8 nativeMultiSigTag
<> toCBOR x) msig
-- | Magic number representing the tag of the native multi-signature script
-- language. For each script language included, a new tag is chosen and the tag
-- is included in the script hash for a script.
nativeMultiSigTag :: Word8
nativeMultiSigTag = 0
instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) =>
MultiSignatureScript (MultiSig hashAlgo dsignAlgo) hashAlgo dsignAlgo where
validateScript = validateNativeMultiSigScript
hashScript = hashNativeMultiSigScript
-- | Multi-signature script witness accessor function for Transactions
txwitsScript
:: Tx hashAlgo dsignAlgo
-> Map.Map (ScriptHash hashAlgo dsignAlgo) (MultiSig hashAlgo dsignAlgo)
txwitsScript = _witnessMSigMap
extractKeyHash
:: [StakeCredential hashAlgo dsignAlgo]
-> [AnyKeyHash hashAlgo dsignAlgo]
extractKeyHash =
mapMaybe (\case
KeyHashObj hk -> Just $ undiscriminateKeyHash hk
GenesisHashObj hk -> Just $ undiscriminateKeyHash hk
_ -> Nothing)
extractScriptHash
:: [StakeCredential hashAlgo dsignAlgo]
-> [ScriptHash hashAlgo dsignAlgo]
extractScriptHash =
mapMaybe (\case
ScriptHashObj hk -> Just hk
_ -> Nothing)