github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/common/validation/statebased/validator_keylevel_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package statebased 8 9 import ( 10 "fmt" 11 "testing" 12 13 "github.com/hechain20/hechain/common/errors" 14 "github.com/hechain20/hechain/core/ledger" 15 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 16 "github.com/hechain20/hechain/protoutil" 17 "github.com/hyperledger/fabric-protos-go/common" 18 pb "github.com/hyperledger/fabric-protos-go/peer" 19 "github.com/stretchr/testify/require" 20 ) 21 22 type mockPolicyEvaluator struct { 23 EvaluateRV error 24 EvaluateResByPolicy map[string]error 25 } 26 27 func (m *mockPolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*protoutil.SignedData) error { 28 if res, ok := m.EvaluateResByPolicy[string(policyBytes)]; ok { 29 return res 30 } 31 32 return m.EvaluateRV 33 } 34 35 func buildBlockWithTxs(txs ...[]byte) *common.Block { 36 return &common.Block{ 37 Header: &common.BlockHeader{ 38 Number: 1, 39 }, 40 Data: &common.BlockData{ 41 Data: txs, 42 }, 43 } 44 } 45 46 func buildTXWithRwset(rws []byte) []byte { 47 return protoutil.MarshalOrPanic(&common.Envelope{ 48 Payload: protoutil.MarshalOrPanic( 49 &common.Payload{ 50 Data: protoutil.MarshalOrPanic( 51 &pb.Transaction{ 52 Actions: []*pb.TransactionAction{ 53 { 54 Payload: protoutil.MarshalOrPanic(&pb.ChaincodeActionPayload{ 55 Action: &pb.ChaincodeEndorsedAction{ 56 ProposalResponsePayload: protoutil.MarshalOrPanic( 57 &pb.ProposalResponsePayload{ 58 Extension: protoutil.MarshalOrPanic(&pb.ChaincodeAction{Results: rws}), 59 }, 60 ), 61 }, 62 }), 63 }, 64 }, 65 }, 66 ), 67 }, 68 ), 69 }) 70 } 71 72 func rwsetBytes(t *testing.T, cc string) []byte { 73 rwsb := rwsetutil.NewRWSetBuilder() 74 rwsb.AddToWriteSet(cc, "key", []byte("value")) 75 rws := rwsb.GetTxReadWriteSet() 76 rwsetbytes, err := rws.ToProtoBytes() 77 require.NoError(t, err) 78 79 return rwsetbytes 80 } 81 82 func TestKeylevelValidation(t *testing.T) { 83 t.Parallel() 84 85 // Scenario: we validate a transaction that writes 86 // to a key that contains key-level validation params. 87 // We simulate policy check success and failure 88 89 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 90 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}} 91 ms := &mockStateFetcher{FetchStateRv: mr} 92 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 93 pe := &mockPolicyEvaluator{} 94 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 95 96 rwsb := rwsetBytes(t, "cc") 97 prp := []byte("barf") 98 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 99 100 validator.PreValidate(1, block) 101 102 endorsements := []*pb.Endorsement{ 103 { 104 Signature: []byte("signature"), 105 Endorser: []byte("endorser"), 106 }, 107 } 108 109 go func() { 110 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 111 }() 112 113 err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), endorsements) 114 require.NoError(t, err) 115 116 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 117 118 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), endorsements) 119 require.Error(t, err) 120 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 121 } 122 123 func TestKeylevelValidationPvtData(t *testing.T) { 124 t.Parallel() 125 126 // Scenario: we validate a transaction that writes 127 // to a pvt key that contains key-level validation params. 128 // We simulate policy check success and failure 129 130 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 131 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}} 132 ms := &mockStateFetcher{FetchStateRv: mr} 133 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 134 pe := &mockPolicyEvaluator{} 135 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 136 137 rwsbu := rwsetutil.NewRWSetBuilder() 138 rwsbu.AddToPvtAndHashedWriteSet("cc", "coll", "key", []byte("value")) 139 rws := rwsbu.GetTxReadWriteSet() 140 rwsb, err := rws.ToProtoBytes() 141 require.NoError(t, err) 142 prp := []byte("barf") 143 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 144 145 validator.PreValidate(1, block) 146 147 go func() { 148 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 149 }() 150 151 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 152 require.NoError(t, err) 153 154 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 155 156 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 157 require.Error(t, err) 158 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 159 } 160 161 func TestKeylevelValidationMetaUpdate(t *testing.T) { 162 t.Parallel() 163 164 // Scenario: we validate a transaction that updates 165 // the key-level validation parameters for a key. 166 // We simulate policy check success and failure 167 168 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 169 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}} 170 ms := &mockStateFetcher{FetchStateRv: mr} 171 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 172 pe := &mockPolicyEvaluator{} 173 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 174 175 rwsbu := rwsetutil.NewRWSetBuilder() 176 rwsbu.AddToMetadataWriteSet("cc", "key", map[string][]byte{}) 177 rws := rwsbu.GetTxReadWriteSet() 178 rwsb, err := rws.ToProtoBytes() 179 require.NoError(t, err) 180 prp := []byte("barf") 181 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 182 183 validator.PreValidate(1, block) 184 185 go func() { 186 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 187 }() 188 189 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 190 require.NoError(t, err) 191 192 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 193 194 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 195 require.Error(t, err) 196 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 197 } 198 199 func TestKeylevelValidationPvtMetaUpdate(t *testing.T) { 200 t.Parallel() 201 202 // Scenario: we validate a transaction that updates 203 // the key-level validation parameters for a pvt key. 204 // We simulate policy check success and failure 205 206 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 207 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}} 208 ms := &mockStateFetcher{FetchStateRv: mr} 209 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 210 pe := &mockPolicyEvaluator{} 211 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 212 213 rwsbu := rwsetutil.NewRWSetBuilder() 214 rwsbu.AddToHashedMetadataWriteSet("cc", "coll", "key", map[string][]byte{}) 215 rws := rwsbu.GetTxReadWriteSet() 216 rwsb, err := rws.ToProtoBytes() 217 require.NoError(t, err) 218 prp := []byte("barf") 219 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 220 221 validator.PreValidate(1, block) 222 223 go func() { 224 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 225 }() 226 227 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 228 require.NoError(t, err) 229 230 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 231 232 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 233 require.Error(t, err) 234 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 235 } 236 237 func TestKeylevelValidationPolicyRetrievalFailure(t *testing.T) { 238 t.Parallel() 239 240 // Scenario: we validate a transaction that updates 241 // the key-level validation parameters for a key. 242 // we simulate the case where we fail to retrieve 243 // the validation parameters from the ledger. 244 245 mr := &mockState{GetStateMetadataErr: fmt.Errorf("metadata retrieval failure")} 246 ms := &mockStateFetcher{FetchStateRv: mr} 247 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 248 validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm) 249 250 rwsb := rwsetBytes(t, "cc") 251 prp := []byte("barf") 252 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 253 254 validator.PreValidate(1, block) 255 256 go func() { 257 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 258 }() 259 260 err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 261 require.Error(t, err) 262 require.IsType(t, &errors.VSCCExecutionFailureError{}, err) 263 } 264 265 func TestKeylevelValidationLedgerFailures(t *testing.T) { 266 // Scenario: we validate a transaction that updates 267 // the key-level validation parameters for a key. 268 // we simulate the case where we fail to retrieve 269 // the validation parameters from the ledger with 270 // both deterministic and non-deterministic errors 271 272 rwsb := rwsetBytes(t, "cc") 273 prp := []byte("barf") 274 275 t.Run("CollConfigNotDefinedError", func(t *testing.T) { 276 mr := &mockState{GetStateMetadataErr: &ledger.CollConfigNotDefinedError{Ns: "mycc"}} 277 ms := &mockStateFetcher{FetchStateRv: mr} 278 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 279 validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm) 280 281 err := validator.Validate("cc", 1, 0, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 282 require.NoError(t, err) 283 }) 284 285 t.Run("InvalidCollNameError", func(t *testing.T) { 286 mr := &mockState{GetStateMetadataErr: &ledger.InvalidCollNameError{Ns: "mycc", Coll: "mycoll"}} 287 ms := &mockStateFetcher{FetchStateRv: mr} 288 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 289 validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm) 290 291 err := validator.Validate("cc", 1, 0, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 292 require.NoError(t, err) 293 }) 294 295 t.Run("I/O error", func(t *testing.T) { 296 mr := &mockState{GetStateMetadataErr: fmt.Errorf("some I/O error")} 297 ms := &mockStateFetcher{FetchStateRv: mr} 298 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 299 validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm) 300 301 err := validator.Validate("cc", 1, 0, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 302 require.Error(t, err) 303 require.IsType(t, &errors.VSCCExecutionFailureError{}, err) 304 }) 305 } 306 307 func TestCCEPValidation(t *testing.T) { 308 t.Parallel() 309 310 // Scenario: we validate a transaction that doesn't 311 // touch any key with a state-based endorsement policy; 312 // we expect to check the normal cc-endorsement policy. 313 314 mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataByHashRv: map[string][]byte{}} 315 ms := &mockStateFetcher{FetchStateRv: mr} 316 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 317 pe := &mockPolicyEvaluator{} 318 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 319 320 rwsbu := rwsetutil.NewRWSetBuilder() 321 rwsbu.AddToWriteSet("cc", "key", []byte("value")) 322 rwsbu.AddToWriteSet("cc", "key1", []byte("value")) 323 rwsbu.AddToReadSet("cc", "readkey", nil) 324 rwsbu.AddToHashedReadSet("cc", "coll", "readpvtkey", nil) 325 rws := rwsbu.GetTxReadWriteSet() 326 rwsb, err := rws.ToProtoBytes() 327 require.NoError(t, err) 328 prp := []byte("barf") 329 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 330 331 validator.PreValidate(1, block) 332 333 go func() { 334 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 335 }() 336 337 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 338 require.NoError(t, err) 339 340 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 341 342 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 343 require.Error(t, err) 344 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 345 } 346 347 func TestCCEPValidationReads(t *testing.T) { 348 t.Parallel() 349 350 // Scenario: we validate a transaction that doesn't 351 // touch any key with a state-based endorsement policy; 352 // we expect to check the normal cc-endorsement policy. 353 354 mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataByHashRv: map[string][]byte{}} 355 ms := &mockStateFetcher{FetchStateRv: mr} 356 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 357 pe := &mockPolicyEvaluator{} 358 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 359 360 rwsbu := rwsetutil.NewRWSetBuilder() 361 rwsbu.AddToReadSet("cc", "readkey", nil) 362 rws := rwsbu.GetTxReadWriteSet() 363 rwsb, err := rws.ToProtoBytes() 364 require.NoError(t, err) 365 prp := []byte("barf") 366 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 367 368 validator.PreValidate(1, block) 369 370 go func() { 371 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 372 }() 373 374 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 375 require.NoError(t, err) 376 377 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 378 379 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 380 require.Error(t, err) 381 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 382 } 383 384 func TestOnlySBEPChecked(t *testing.T) { 385 t.Parallel() 386 387 // Scenario: we ensure that as long as there is one key that 388 // requires state-based endorsement, we only check that policy 389 // and we do not check the cc-EP. We check that by setting up the 390 // policy evaluator mock into returning an error for all policies 391 // but the state-based one, and expect successful evaluation 392 393 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 394 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("SBEP")}} 395 ms := &mockStateFetcher{FetchStateRv: mr} 396 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 397 pe := &mockPolicyEvaluator{} 398 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 399 400 rwsb := rwsetBytes(t, "cc") 401 prp := []byte("barf") 402 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 403 404 validator.PreValidate(1, block) 405 406 go func() { 407 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 408 }() 409 410 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 411 pe.EvaluateResByPolicy = map[string]error{ 412 "SBEP": nil, 413 } 414 415 err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 416 require.NoError(t, err) 417 418 // we also test with a read-write set that has a read as well as a write 419 rwsbu := rwsetutil.NewRWSetBuilder() 420 rwsbu.AddToWriteSet("cc", "key", []byte("value")) 421 rwsbu.AddToReadSet("cc", "key", nil) 422 rws := rwsbu.GetTxReadWriteSet() 423 rwsb, _ = rws.ToProtoBytes() 424 425 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 426 require.NoError(t, err) 427 } 428 429 func TestCCEPValidationPvtReads(t *testing.T) { 430 t.Parallel() 431 432 // Scenario: we validate a transaction that doesn't 433 // touch any key with a state-based endorsement policy; 434 // we expect to check the normal cc-endorsement policy. 435 436 mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataByHashRv: map[string][]byte{}} 437 ms := &mockStateFetcher{FetchStateRv: mr} 438 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 439 pe := &mockPolicyEvaluator{} 440 validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm) 441 442 rwsbu := rwsetutil.NewRWSetBuilder() 443 rwsbu.AddToHashedReadSet("cc", "coll", "readpvtkey", nil) 444 rws := rwsbu.GetTxReadWriteSet() 445 rwsb, err := rws.ToProtoBytes() 446 require.NoError(t, err) 447 prp := []byte("barf") 448 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 449 450 validator.PreValidate(1, block) 451 452 go func() { 453 validator.PostValidate("cc", 1, 0, fmt.Errorf("")) 454 }() 455 456 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 457 require.NoError(t, err) 458 459 pe.EvaluateRV = fmt.Errorf("policy evaluation error") 460 461 err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 462 require.Error(t, err) 463 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 464 } 465 466 func TestKeylevelValidationFailure(t *testing.T) { 467 t.Parallel() 468 469 // Scenario: we validate a transaction that writes 470 // to a key that contains key-level validation params. 471 // Validation fails because the block contains a previous 472 // transaction that updates the key-level validation params 473 // for that very same key. 474 475 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 476 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}} 477 ms := &mockStateFetcher{FetchStateRv: mr} 478 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 479 validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm) 480 481 rwsb := rwsetBytes(t, "cc") 482 prp := []byte("barf") 483 block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key"))) 484 485 validator.PreValidate(1, block) 486 487 go func() { 488 validator.PostValidate("cc", 1, 0, nil) 489 }() 490 491 err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{}) 492 require.Error(t, err) 493 require.IsType(t, &errors.VSCCEndorsementPolicyError{}, err) 494 }