github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/storage/mru/update.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package mru 18 19 import ( 20 "encoding/binary" 21 "errors" 22 23 "github.com/FusionFoundation/efsn/swarm/chunk" 24 "github.com/FusionFoundation/efsn/swarm/log" 25 "github.com/FusionFoundation/efsn/swarm/multihash" 26 ) 27 28 // resourceUpdate encapsulates the information sent as part of a resource update 29 type resourceUpdate struct { 30 updateHeader // metainformationa about this resource update 31 data []byte // actual data payload 32 } 33 34 // Update chunk layout 35 // Prefix: 36 // 2 bytes updateHeaderLength 37 // 2 bytes data length 38 const chunkPrefixLength = 2 + 2 39 40 // Header: (see updateHeader) 41 // Data: 42 // data (datalength bytes) 43 // 44 // Minimum size is Header + 1 (minimum data length, enforced) 45 const minimumUpdateDataLength = updateHeaderLength + 1 46 const maxUpdateDataLength = chunk.DefaultSize - signatureLength - updateHeaderLength - chunkPrefixLength 47 48 // binaryPut serializes the resource update information into the given slice 49 func (r *resourceUpdate) binaryPut(serializedData []byte) error { 50 datalength := len(r.data) 51 if datalength == 0 { 52 return NewError(ErrInvalidValue, "cannot update a resource with no data") 53 } 54 55 if datalength > maxUpdateDataLength { 56 return NewErrorf(ErrInvalidValue, "data is too big (length=%d). Max length=%d", datalength, maxUpdateDataLength) 57 } 58 59 if len(serializedData) != r.binaryLength() { 60 return NewErrorf(ErrInvalidValue, "slice passed to putBinary must be of exact size. Expected %d bytes", r.binaryLength()) 61 } 62 63 if r.multihash { 64 if _, _, err := multihash.GetMultihashLength(r.data); err != nil { 65 return NewError(ErrInvalidValue, "Invalid multihash") 66 } 67 } 68 69 // Add prefix: updateHeaderLength and actual data length 70 cursor := 0 71 binary.LittleEndian.PutUint16(serializedData[cursor:], uint16(updateHeaderLength)) 72 cursor += 2 73 74 // data length 75 binary.LittleEndian.PutUint16(serializedData[cursor:], uint16(datalength)) 76 cursor += 2 77 78 // serialize header (see updateHeader) 79 if err := r.updateHeader.binaryPut(serializedData[cursor : cursor+updateHeaderLength]); err != nil { 80 return err 81 } 82 cursor += updateHeaderLength 83 84 // add the data 85 copy(serializedData[cursor:], r.data) 86 cursor += datalength 87 88 return nil 89 } 90 91 // binaryLength returns the expected number of bytes this structure will take to encode 92 func (r *resourceUpdate) binaryLength() int { 93 return chunkPrefixLength + updateHeaderLength + len(r.data) 94 } 95 96 // binaryGet populates this instance from the information contained in the passed byte slice 97 func (r *resourceUpdate) binaryGet(serializedData []byte) error { 98 if len(serializedData) < minimumUpdateDataLength { 99 return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a resource update chunk", minimumUpdateDataLength) 100 } 101 cursor := 0 102 declaredHeaderlength := binary.LittleEndian.Uint16(serializedData[cursor : cursor+2]) 103 if declaredHeaderlength != updateHeaderLength { 104 return NewErrorf(ErrCorruptData, "Invalid header length. Expected %d, got %d", updateHeaderLength, declaredHeaderlength) 105 } 106 107 cursor += 2 108 datalength := int(binary.LittleEndian.Uint16(serializedData[cursor : cursor+2])) 109 cursor += 2 110 111 if chunkPrefixLength+updateHeaderLength+datalength+signatureLength != len(serializedData) { 112 return NewError(ErrNothingToReturn, "length specified in header is different than actual chunk size") 113 } 114 115 // at this point we can be satisfied that we have the correct data length to read 116 if err := r.updateHeader.binaryGet(serializedData[cursor : cursor+updateHeaderLength]); err != nil { 117 return err 118 } 119 cursor += updateHeaderLength 120 121 data := serializedData[cursor : cursor+datalength] 122 cursor += datalength 123 124 // if multihash content is indicated we check the validity of the multihash 125 if r.updateHeader.multihash { 126 mhLength, mhHeaderLength, err := multihash.GetMultihashLength(data) 127 if err != nil { 128 log.Error("multihash parse error", "err", err) 129 return err 130 } 131 if datalength != mhLength+mhHeaderLength { 132 log.Debug("multihash error", "datalength", datalength, "mhLength", mhLength, "mhHeaderLength", mhHeaderLength) 133 return errors.New("Corrupt multihash data") 134 } 135 } 136 137 // now that all checks have passed, copy data into structure 138 r.data = make([]byte, datalength) 139 copy(r.data, data) 140 141 return nil 142 143 } 144 145 // Multihash specifies whether the resource data should be interpreted as multihash 146 func (r *resourceUpdate) Multihash() bool { 147 return r.multihash 148 }