github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/mru/metadata.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:50</date> 10 //</624342683220971520> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package mru 29 30 import ( 31 "encoding/binary" 32 "hash" 33 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/swarm/storage" 36 ) 37 38 // 39 // 40 type ResourceMetadata struct { 41 StartTime Timestamp // 42 Frequency uint64 // 43 Name string // 44 Owner common.Address // 45 } 46 47 const frequencyLength = 8 // 48 const nameLengthLength = 1 49 50 // 51 // 52 // 53 // 54 // 55 // 56 // 57 const minimumMetadataLength = chunkPrefixLength + timestampLength + frequencyLength + nameLengthLength + common.AddressLength 58 59 // 60 func (r *ResourceMetadata) binaryGet(serializedData []byte) error { 61 if len(serializedData) < minimumMetadataLength { 62 return NewErrorf(ErrInvalidValue, "Metadata chunk to deserialize is too short. Expected at least %d. Got %d.", minimumMetadataLength, len(serializedData)) 63 } 64 65 // 66 if serializedData[0] != 0 || serializedData[1] != 0 { 67 return NewError(ErrCorruptData, "Invalid metadata chunk") 68 } 69 70 cursor := 2 71 metadataLength := int(binary.LittleEndian.Uint16(serializedData[cursor : cursor+2])) // 72 if metadataLength+chunkPrefixLength != len(serializedData) { 73 return NewErrorf(ErrCorruptData, "Incorrect declared metadata length. Expected %d, got %d.", metadataLength+chunkPrefixLength, len(serializedData)) 74 } 75 76 cursor += 2 77 78 if err := r.StartTime.binaryGet(serializedData[cursor : cursor+timestampLength]); err != nil { 79 return err 80 } 81 cursor += timestampLength 82 83 r.Frequency = binary.LittleEndian.Uint64(serializedData[cursor : cursor+frequencyLength]) 84 cursor += frequencyLength 85 86 nameLength := int(serializedData[cursor]) 87 if nameLength+minimumMetadataLength > len(serializedData) { 88 return NewErrorf(ErrInvalidValue, "Metadata chunk to deserialize is too short when decoding resource name. Expected at least %d. Got %d.", nameLength+minimumMetadataLength, len(serializedData)) 89 } 90 cursor++ 91 r.Name = string(serializedData[cursor : cursor+nameLength]) 92 cursor += nameLength 93 94 copy(r.Owner[:], serializedData[cursor:]) 95 cursor += common.AddressLength 96 if cursor != len(serializedData) { 97 return NewErrorf(ErrInvalidValue, "Metadata chunk has leftover data after deserialization. %d left to read", len(serializedData)-cursor) 98 } 99 return nil 100 } 101 102 // 103 func (r *ResourceMetadata) binaryPut(serializedData []byte) error { 104 metadataChunkLength := r.binaryLength() 105 if len(serializedData) != metadataChunkLength { 106 return NewErrorf(ErrInvalidValue, "Need a slice of exactly %d bytes to serialize this metadata, but got a slice of size %d.", metadataChunkLength, len(serializedData)) 107 } 108 109 // 110 // 111 cursor := 2 112 binary.LittleEndian.PutUint16(serializedData[cursor:cursor+2], uint16(metadataChunkLength-chunkPrefixLength)) // 113 cursor += 2 114 115 r.StartTime.binaryPut(serializedData[cursor : cursor+timestampLength]) 116 cursor += timestampLength 117 118 binary.LittleEndian.PutUint64(serializedData[cursor:cursor+frequencyLength], r.Frequency) 119 cursor += frequencyLength 120 121 // 122 // 123 nameLength := len(r.Name) 124 if nameLength > 255 { 125 nameLength = 255 126 } 127 serializedData[cursor] = uint8(nameLength) 128 cursor++ 129 copy(serializedData[cursor:cursor+nameLength], []byte(r.Name[:nameLength])) 130 cursor += nameLength 131 132 copy(serializedData[cursor:cursor+common.AddressLength], r.Owner[:]) 133 cursor += common.AddressLength 134 135 return nil 136 } 137 138 func (r *ResourceMetadata) binaryLength() int { 139 return minimumMetadataLength + len(r.Name) 140 } 141 142 // 143 // 144 func (r *ResourceMetadata) serializeAndHash() (rootAddr, metaHash []byte, chunkData []byte, err error) { 145 146 chunkData = make([]byte, r.binaryLength()) 147 if err := r.binaryPut(chunkData); err != nil { 148 return nil, nil, nil, err 149 } 150 rootAddr, metaHash = metadataHash(chunkData) 151 return rootAddr, metaHash, chunkData, nil 152 153 } 154 155 // 156 func (metadata *ResourceMetadata) newChunk() (chunk *storage.Chunk, metaHash []byte, err error) { 157 // 158 // 159 // 160 // 161 162 // 163 // 164 // 165 rootAddr, metaHash, chunkData, err := metadata.serializeAndHash() 166 if err != nil { 167 return nil, nil, err 168 } 169 170 // 171 chunk = storage.NewChunk(rootAddr, nil) 172 chunk.SData = chunkData 173 chunk.Size = int64(len(chunkData)) 174 175 return chunk, metaHash, nil 176 } 177 178 // 179 // 180 // 181 // 182 // 183 // 184 // 185 // 186 // 187 // 188 // 189 func metadataHash(chunkData []byte) (rootAddr, metaHash []byte) { 190 hasher := hashPool.Get().(hash.Hash) 191 defer hashPool.Put(hasher) 192 hasher.Reset() 193 hasher.Write(chunkData[:len(chunkData)-common.AddressLength]) 194 metaHash = hasher.Sum(nil) 195 hasher.Reset() 196 hasher.Write(metaHash) 197 hasher.Write(chunkData[len(chunkData)-common.AddressLength:]) 198 rootAddr = hasher.Sum(nil) 199 return 200 } 201