github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/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/ethereum/go-ethereum/swarm/log" 24 "github.com/ethereum/go-ethereum/swarm/multihash" 25 ) 26 27 // resourceUpdate encapsulates the information sent as part of a resource update 28 type resourceUpdate struct { 29 updateHeader // metainformationa about this resource update 30 data []byte // actual data payload 31 } 32 33 // Update chunk layout 34 // Prefix: 35 // 2 bytes updateHeaderLength 36 // 2 bytes data length 37 const chunkPrefixLength = 2 + 2 38 39 // Header: (see updateHeader) 40 // Data: 41 // data (datalength bytes) 42 // 43 // Minimum size is Header + 1 (minimum data length, enforced) 44 const minimumUpdateDataLength = updateHeaderLength + 1 45 const maxUpdateDataLength = chunkSize - signatureLength - updateHeaderLength - chunkPrefixLength 46 47 // binaryPut serializes the resource update information into the given slice 48 func (r *resourceUpdate) binaryPut(serializedData []byte) error { 49 datalength := len(r.data) 50 if datalength == 0 { 51 return NewError(ErrInvalidValue, "cannot update a resource with no data") 52 } 53 54 if datalength > maxUpdateDataLength { 55 return NewErrorf(ErrInvalidValue, "data is too big (length=%d). Max length=%d", datalength, maxUpdateDataLength) 56 } 57 58 if len(serializedData) != r.binaryLength() { 59 return NewErrorf(ErrInvalidValue, "slice passed to putBinary must be of exact size. Expected %d bytes", r.binaryLength()) 60 } 61 62 if r.multihash { 63 if _, _, err := multihash.GetMultihashLength(r.data); err != nil { 64 return NewError(ErrInvalidValue, "Invalid multihash") 65 } 66 } 67 68 // Add prefix: updateHeaderLength and actual data length 69 cursor := 0 70 binary.LittleEndian.PutUint16(serializedData[cursor:], uint16(updateHeaderLength)) 71 cursor += 2 72 73 // data length 74 binary.LittleEndian.PutUint16(serializedData[cursor:], uint16(datalength)) 75 cursor += 2 76 77 // serialize header (see updateHeader) 78 if err := r.updateHeader.binaryPut(serializedData[cursor : cursor+updateHeaderLength]); err != nil { 79 return err 80 } 81 cursor += updateHeaderLength 82 83 // add the data 84 copy(serializedData[cursor:], r.data) 85 cursor += datalength 86 87 return nil 88 } 89 90 // binaryLength returns the expected number of bytes this structure will take to encode 91 func (r *resourceUpdate) binaryLength() int { 92 return chunkPrefixLength + updateHeaderLength + len(r.data) 93 } 94 95 // binaryGet populates this instance from the information contained in the passed byte slice 96 func (r *resourceUpdate) binaryGet(serializedData []byte) error { 97 if len(serializedData) < minimumUpdateDataLength { 98 return NewErrorf(ErrNothingToReturn, "chunk less than %d bytes cannot be a resource update chunk", minimumUpdateDataLength) 99 } 100 cursor := 0 101 declaredHeaderlength := binary.LittleEndian.Uint16(serializedData[cursor : cursor+2]) 102 if declaredHeaderlength != updateHeaderLength { 103 return NewErrorf(ErrCorruptData, "Invalid header length. Expected %d, got %d", updateHeaderLength, declaredHeaderlength) 104 } 105 106 cursor += 2 107 datalength := int(binary.LittleEndian.Uint16(serializedData[cursor : cursor+2])) 108 cursor += 2 109 110 if chunkPrefixLength+updateHeaderLength+datalength+signatureLength != len(serializedData) { 111 return NewError(ErrNothingToReturn, "length specified in header is different than actual chunk size") 112 } 113 114 // at this point we can be satisfied that we have the correct data length to read 115 if err := r.updateHeader.binaryGet(serializedData[cursor : cursor+updateHeaderLength]); err != nil { 116 return err 117 } 118 cursor += updateHeaderLength 119 120 data := serializedData[cursor : cursor+datalength] 121 cursor += datalength 122 123 // if multihash content is indicated we check the validity of the multihash 124 if r.updateHeader.multihash { 125 mhLength, mhHeaderLength, err := multihash.GetMultihashLength(data) 126 if err != nil { 127 log.Error("multihash parse error", "err", err) 128 return err 129 } 130 if datalength != mhLength+mhHeaderLength { 131 log.Debug("multihash error", "datalength", datalength, "mhLength", mhLength, "mhHeaderLength", mhHeaderLength) 132 return errors.New("Corrupt multihash data") 133 } 134 } 135 136 // now that all checks have passed, copy data into structure 137 r.data = make([]byte, datalength) 138 copy(r.data, data) 139 140 return nil 141 142 } 143 144 // Multihash specifies whether the resource data should be interpreted as multihash 145 func (r *resourceUpdate) Multihash() bool { 146 return r.multihash 147 }