git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/erasurecode/verify.go (about) 1 package erasurecode 2 3 import ( 4 "fmt" 5 6 objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 7 ) 8 9 // Verify verifies that parts are well formed. 10 // All parts are expected to be non-nil. 11 // The number of parts must be equal to `total` field of the EC header 12 // and parts must be sorted by index. 13 func (c *Constructor) Verify(parts []*objectSDK.Object) error { 14 c.clear() 15 16 var headerLength int 17 for i := range parts { 18 if parts[i] == nil { 19 return ErrMalformedSlice 20 } 21 22 var err error 23 headerLength, err = validatePart(parts, i, headerLength) 24 if err != nil { 25 return err 26 } 27 } 28 29 p0 := parts[0] 30 for i := 1; i < len(parts); i++ { 31 // This part must be kept in sync with copyRequiredFields(). 32 pi := parts[i] 33 if p0.OwnerID().Equals(pi.OwnerID()) { 34 return fmt.Errorf("%w: owner id mismatch: %s != %s", ErrMalformedSlice, p0.OwnerID(), pi.OwnerID()) 35 } 36 if p0.Version() == nil && pi.Version() != nil || !p0.Version().Equal(*pi.Version()) { 37 return fmt.Errorf("%w: version mismatch: %s != %s", ErrMalformedSlice, p0.Version(), pi.Version()) 38 } 39 40 cnr0, _ := p0.ContainerID() 41 cnri, _ := pi.ContainerID() 42 if !cnr0.Equals(cnri) { 43 return fmt.Errorf("%w: container id mismatch: %s != %s", ErrMalformedSlice, cnr0, cnri) 44 } 45 } 46 47 if err := c.fillHeader(parts); err != nil { 48 return err 49 } 50 c.fillPayload(parts) 51 52 ok, err := c.enc.Verify(c.headerShards) 53 if err != nil { 54 return err 55 } 56 if !ok { 57 return ErrMalformedSlice 58 } 59 60 ok, err = c.enc.Verify(c.payloadShards) 61 if err != nil { 62 return err 63 } 64 if !ok { 65 return ErrMalformedSlice 66 } 67 return nil 68 } 69 70 // copyRequiredFields sets all fields in dst which are copied from src and shared among all chunks. 71 // src can be either another chunk of full object. 72 // dst must be a chunk. 73 func copyRequiredFields(dst *objectSDK.Object, src *objectSDK.Object) { 74 dst.SetVersion(src.Version()) 75 dst.SetOwnerID(src.OwnerID()) 76 dst.SetCreationEpoch(src.CreationEpoch()) 77 dst.SetSessionToken(src.SessionToken()) 78 79 cnr, _ := src.ContainerID() 80 dst.SetContainerID(cnr) 81 } 82 83 // validatePart makes i-th part is consistent with the rest. 84 // If headerLength is not zero it is asserted to be equal in the ec header. 85 // Otherwise, new headerLength is returned. 86 func validatePart(parts []*objectSDK.Object, i int, headerLength int) (int, error) { 87 ec := parts[i].GetECHeader() 88 if ec == nil { 89 return headerLength, fmt.Errorf("%w: missing EC header", ErrMalformedSlice) 90 } 91 if ec.Index() != uint32(i) { 92 return headerLength, fmt.Errorf("%w: index=%d, ec.index=%d", ErrMalformedSlice, i, ec.Index()) 93 } 94 if ec.Total() != uint32(len(parts)) { 95 return headerLength, fmt.Errorf("%w: len(parts)=%d, total=%d", ErrMalformedSlice, len(parts), ec.Total()) 96 } 97 if headerLength == 0 { 98 return int(ec.HeaderLength()), nil 99 } 100 if ec.HeaderLength() != uint32(headerLength) { 101 return headerLength, fmt.Errorf("%w: header length mismatch %d != %d", ErrMalformedSlice, headerLength, ec.HeaderLength()) 102 } 103 return headerLength, nil 104 }