github.com/koko1123/flow-go-1@v0.29.6/access/validator.go (about) 1 package access 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/onflow/flow-go/crypto" 8 9 "github.com/onflow/cadence/runtime/parser" 10 11 "github.com/koko1123/flow-go-1/model/flow" 12 "github.com/koko1123/flow-go-1/state/protocol" 13 "github.com/koko1123/flow-go-1/storage" 14 ) 15 16 type Blocks interface { 17 HeaderByID(id flow.Identifier) (*flow.Header, error) 18 FinalizedHeader() (*flow.Header, error) 19 } 20 21 type ProtocolStateBlocks struct { 22 state protocol.State 23 } 24 25 func NewProtocolStateBlocks(state protocol.State) *ProtocolStateBlocks { 26 return &ProtocolStateBlocks{state: state} 27 } 28 29 func (b *ProtocolStateBlocks) HeaderByID(id flow.Identifier) (*flow.Header, error) { 30 header, err := b.state.AtBlockID(id).Head() 31 if err != nil { 32 if errors.Is(err, storage.ErrNotFound) { 33 return nil, nil 34 } 35 36 return nil, err 37 } 38 39 return header, nil 40 } 41 42 func (b *ProtocolStateBlocks) FinalizedHeader() (*flow.Header, error) { 43 return b.state.Final().Head() 44 } 45 46 type TransactionValidationOptions struct { 47 Expiry uint 48 ExpiryBuffer uint 49 AllowEmptyReferenceBlockID bool 50 AllowUnknownReferenceBlockID bool 51 MaxGasLimit uint64 52 CheckScriptsParse bool 53 MaxTransactionByteSize uint64 54 MaxCollectionByteSize uint64 55 } 56 57 type TransactionValidator struct { 58 blocks Blocks // for looking up blocks to check transaction expiry 59 chain flow.Chain // for checking validity of addresses 60 options TransactionValidationOptions 61 serviceAccountAddress flow.Address 62 } 63 64 func NewTransactionValidator( 65 blocks Blocks, 66 chain flow.Chain, 67 options TransactionValidationOptions, 68 ) *TransactionValidator { 69 return &TransactionValidator{ 70 blocks: blocks, 71 chain: chain, 72 options: options, 73 serviceAccountAddress: chain.ServiceAddress(), 74 } 75 } 76 77 func (v *TransactionValidator) Validate(tx *flow.TransactionBody) (err error) { 78 err = v.checkTxSizeLimit(tx) 79 if err != nil { 80 return err 81 } 82 83 err = v.checkMissingFields(tx) 84 if err != nil { 85 return err 86 } 87 88 err = v.checkGasLimit(tx) 89 if err != nil { 90 return err 91 } 92 93 err = v.checkExpiry(tx) 94 if err != nil { 95 return err 96 } 97 98 err = v.checkCanBeParsed(tx) 99 if err != nil { 100 return err 101 } 102 103 err = v.checkAddresses(tx) 104 if err != nil { 105 return err 106 } 107 108 err = v.checkSignatureFormat(tx) 109 if err != nil { 110 return err 111 } 112 113 err = v.checkSignatureDuplications(tx) 114 if err != nil { 115 return err 116 } 117 118 // TODO replace checkSignatureFormat by verifying the account/payer signatures 119 120 return nil 121 } 122 123 func (v *TransactionValidator) checkTxSizeLimit(tx *flow.TransactionBody) error { 124 txSize := uint64(tx.ByteSize()) 125 // first check compatibility to collection byte size 126 // this guarantees liveness 127 if txSize >= v.options.MaxCollectionByteSize { 128 return InvalidTxByteSizeError{ 129 Actual: txSize, 130 Maximum: v.options.MaxCollectionByteSize, 131 } 132 } 133 // this logic need the reason we don't greenlist the service account against the collection size 134 // limits is we can't verify the signature here yet. 135 if tx.Payer == v.serviceAccountAddress { 136 return nil 137 } 138 if txSize > v.options.MaxTransactionByteSize { 139 return InvalidTxByteSizeError{ 140 Actual: txSize, 141 Maximum: v.options.MaxTransactionByteSize, 142 } 143 } 144 return nil 145 } 146 147 func (v *TransactionValidator) checkMissingFields(tx *flow.TransactionBody) error { 148 missingFields := tx.MissingFields() 149 150 if v.options.AllowEmptyReferenceBlockID { 151 missingFields = remove(missingFields, flow.TransactionFieldRefBlockID.String()) 152 } 153 154 if len(missingFields) > 0 { 155 return IncompleteTransactionError{MissingFields: missingFields} 156 } 157 158 return nil 159 } 160 161 func (v *TransactionValidator) checkGasLimit(tx *flow.TransactionBody) error { 162 // if service account is the payer of the transaction accepts any gas limit 163 // note that even though we don't enforce any limit here, exec node later 164 // enforce a max value for any transaction 165 if tx.Payer == v.serviceAccountAddress { 166 return nil 167 } 168 if tx.GasLimit > v.options.MaxGasLimit || tx.GasLimit == 0 { 169 return InvalidGasLimitError{ 170 Actual: tx.GasLimit, 171 Maximum: v.options.MaxGasLimit, 172 } 173 } 174 175 return nil 176 } 177 178 // checkExpiry checks whether a transaction's reference block ID is 179 // valid. Returns nil if the reference is valid, returns an error if the 180 // reference is invalid or we failed to check it. 181 func (v *TransactionValidator) checkExpiry(tx *flow.TransactionBody) error { 182 if tx.ReferenceBlockID == flow.ZeroID && v.options.AllowEmptyReferenceBlockID { 183 return nil 184 } 185 186 // look up the reference block 187 ref, err := v.blocks.HeaderByID(tx.ReferenceBlockID) 188 if err != nil { 189 return fmt.Errorf("could not get reference block: %w", err) 190 } 191 192 if ref == nil { 193 // the transaction references an unknown block - at this point we decide 194 // whether to consider it expired based on configuration 195 if v.options.AllowUnknownReferenceBlockID { 196 return nil 197 } 198 199 return ErrUnknownReferenceBlock 200 } 201 202 // get the latest finalized block we know about 203 final, err := v.blocks.FinalizedHeader() 204 if err != nil { 205 return fmt.Errorf("could not get finalized header: %w", err) 206 } 207 208 diff := final.Height - ref.Height 209 // check for overflow 210 if ref.Height > final.Height { 211 diff = 0 212 } 213 214 // discard transactions that are expired, or that will expire sooner than 215 // our configured buffer allows 216 if uint(diff) > v.options.Expiry-v.options.ExpiryBuffer { 217 return ExpiredTransactionError{ 218 RefHeight: ref.Height, 219 FinalHeight: final.Height, 220 } 221 } 222 223 return nil 224 } 225 226 func (v *TransactionValidator) checkCanBeParsed(tx *flow.TransactionBody) error { 227 if v.options.CheckScriptsParse { 228 _, err := parser.ParseProgram(nil, tx.Script, parser.Config{}) 229 if err != nil { 230 return InvalidScriptError{ParserErr: err} 231 } 232 } 233 234 return nil 235 } 236 237 func (v *TransactionValidator) checkAddresses(tx *flow.TransactionBody) error { 238 239 for _, address := range append(tx.Authorizers, tx.Payer) { 240 // we check whether this is a valid output of the address generator 241 if !v.chain.IsValid(address) { 242 return InvalidAddressError{Address: address} 243 } 244 } 245 246 return nil 247 } 248 249 // every key (account, key index combination) can only be used once for signing 250 func (v *TransactionValidator) checkSignatureDuplications(tx *flow.TransactionBody) error { 251 type uniqueKey struct { 252 address flow.Address 253 index uint64 254 } 255 observedSigs := make(map[uniqueKey]bool) 256 for _, sig := range append(tx.PayloadSignatures, tx.EnvelopeSignatures...) { 257 if observedSigs[uniqueKey{sig.Address, sig.KeyIndex}] { 258 return DuplicatedSignatureError{Address: sig.Address, KeyIndex: sig.KeyIndex} 259 } 260 observedSigs[uniqueKey{sig.Address, sig.KeyIndex}] = true 261 } 262 return nil 263 } 264 265 func (v *TransactionValidator) checkSignatureFormat(tx *flow.TransactionBody) error { 266 267 for _, signature := range append(tx.PayloadSignatures, tx.EnvelopeSignatures...) { 268 // check the format of the signature is valid. 269 // a valid signature is an ECDSA signature of either P-256 or secp256k1 curve. 270 ecdsaSignature := signature.Signature 271 272 // check if the signature could be a P-256 signature 273 valid, err := crypto.SignatureFormatCheck(crypto.ECDSAP256, ecdsaSignature) 274 if err != nil { 275 return fmt.Errorf("could not check the signature format (%s): %w", signature, err) 276 } 277 if valid { 278 continue 279 } 280 281 // check if the signature could be a secp256k1 signature 282 valid, err = crypto.SignatureFormatCheck(crypto.ECDSASecp256k1, ecdsaSignature) 283 if err != nil { 284 return fmt.Errorf("could not check the signature format (%s): %w", signature, err) 285 } 286 if valid { 287 continue 288 } 289 290 return InvalidSignatureError{Signature: signature} 291 } 292 293 return nil 294 } 295 296 func remove(s []string, r string) []string { 297 for i, v := range s { 298 if v == r { 299 return append(s[:i], s[i+1:]...) 300 } 301 } 302 return s 303 }