github.com/okex/exchain@v1.8.0/libs/tendermint/types/deltas.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "fmt" 6 "time" 7 8 "github.com/okex/exchain/libs/tendermint/crypto/tmhash" 9 "github.com/okex/exchain/libs/tendermint/libs/compress" 10 "github.com/tendermint/go-amino" 11 ) 12 13 const ( 14 FlagDownloadDDS = "download-delta" 15 FlagUploadDDS = "upload-delta" 16 FlagAppendPid = "append-pid" 17 FlagBufferSize = "delta-buffer-size" 18 FlagDDSCompressType = "compress-type" 19 FlagDDSCompressFlag = "compress-flag" 20 21 // redis 22 // url fmt (ip:port) 23 FlagRedisUrl = "delta-redis-url" 24 FlagRedisAuth = "delta-redis-auth" 25 // expire unit: second 26 FlagRedisExpire = "delta-redis-expire" 27 FlagRedisDB = "delta-redis-db" 28 FlagFastQuery = "fast-query" 29 30 // FlagDeltaVersion specify the DeltaVersion 31 FlagDeltaVersion = "delta-version" 32 ) 33 34 var ( 35 // DeltaVersion do not apply delta if version does not match 36 // if user specify the flag 'FlagDeltaVersion'(--delta-version) use user's setting, 37 // otherwise use the default value 38 DeltaVersion = 10 39 ) 40 41 var ( 42 FastQuery = false 43 DownloadDelta = false 44 UploadDelta = false 45 WasmStoreCode = false 46 ) 47 48 type DeltasMessage struct { 49 Metadata []byte `json:"metadata"` 50 MetadataHash []byte `json:"metadata_hash"` 51 Height int64 `json:"height"` 52 CompressType int `json:"compress_type"` 53 From string `json:"from"` 54 } 55 56 func (m *DeltasMessage) AminoSize(_ *amino.Codec) int { 57 var size int 58 // field 1 59 if len(m.Metadata) != 0 { 60 size += 1 + amino.ByteSliceSize(m.Metadata) 61 } 62 // field 2 63 if len(m.MetadataHash) != 0 { 64 size += 1 + amino.ByteSliceSize(m.MetadataHash) 65 } 66 // field 3 67 if m.Height != 0 { 68 size += 1 + amino.UvarintSize(uint64(m.Height)) 69 } 70 // field 4 71 if m.CompressType != 0 { 72 size += 1 + amino.UvarintSize(uint64(m.CompressType)) 73 } 74 // field 5 75 if m.From != "" { 76 size += 1 + amino.EncodedStringSize(m.From) 77 } 78 return size 79 } 80 81 func (m *DeltasMessage) MarshalToAmino(cdc *amino.Codec) ([]byte, error) { 82 var buf bytes.Buffer 83 buf.Grow(m.AminoSize(cdc)) 84 err := m.MarshalAminoTo(cdc, &buf) 85 if err != nil { 86 return nil, err 87 } 88 return buf.Bytes(), nil 89 } 90 91 func (m *DeltasMessage) MarshalAminoTo(_ *amino.Codec, buf *bytes.Buffer) error { 92 // field 1 93 if len(m.Metadata) != 0 { 94 const pbKey = 1<<3 | 2 95 if err := amino.EncodeByteSliceWithKeyToBuffer(buf, m.Metadata, pbKey); err != nil { 96 return err 97 } 98 } 99 // field 2 100 if len(m.MetadataHash) != 0 { 101 const pbKey = 2<<3 | 2 102 if err := amino.EncodeByteSliceWithKeyToBuffer(buf, m.MetadataHash, pbKey); err != nil { 103 return err 104 } 105 } 106 // field 3 107 if m.Height != 0 { 108 const pbKey = 3 << 3 109 if err := amino.EncodeUvarintWithKeyToBuffer(buf, uint64(m.Height), pbKey); err != nil { 110 return err 111 } 112 } 113 // field 4 114 if m.CompressType != 0 { 115 const pbKey = 4 << 3 116 if err := amino.EncodeUvarintWithKeyToBuffer(buf, uint64(m.CompressType), pbKey); err != nil { 117 return err 118 } 119 } 120 // field 5 121 if m.From != "" { 122 const pbKey = 5<<3 | 2 123 if err := amino.EncodeStringWithKeyToBuffer(buf, m.From, pbKey); err != nil { 124 return err 125 } 126 } 127 return nil 128 } 129 130 func (m *DeltasMessage) UnmarshalFromAmino(_ *amino.Codec, data []byte) error { 131 const fieldCount = 5 132 var currentField int 133 var currentType amino.Typ3 134 var err error 135 136 for cur := 1; cur <= fieldCount; cur++ { 137 if len(data) != 0 && (currentField == 0 || currentField < cur) { 138 var nextField int 139 if nextField, currentType, err = amino.ParseProtoPosAndTypeMustOneByte(data[0]); err != nil { 140 return err 141 } 142 if nextField < currentField { 143 return fmt.Errorf("next field should greater than %d, got %d", currentField, nextField) 144 } else { 145 currentField = nextField 146 } 147 } 148 149 if len(data) == 0 || currentField != cur { 150 switch cur { 151 case 1: 152 m.Metadata = nil 153 case 2: 154 m.MetadataHash = nil 155 case 3: 156 m.Height = 0 157 case 4: 158 m.CompressType = 0 159 case 5: 160 m.From = "" 161 default: 162 return fmt.Errorf("unexpect feild num %d", cur) 163 } 164 } else { 165 pbk := data[0] 166 data = data[1:] 167 var subData []byte 168 if currentType == amino.Typ3_ByteLength { 169 if subData, err = amino.DecodeByteSliceWithoutCopy(&data); err != nil { 170 return err 171 } 172 } 173 switch pbk { 174 case 1<<3 | byte(amino.Typ3_ByteLength): 175 amino.UpdateByteSlice(&m.Metadata, subData) 176 case 2<<3 | byte(amino.Typ3_ByteLength): 177 amino.UpdateByteSlice(&m.MetadataHash, subData) 178 case 3<<3 | byte(amino.Typ3_Varint): 179 if uvint, err := amino.DecodeUvarintUpdateBytes(&data); err != nil { 180 return err 181 } else { 182 m.Height = int64(uvint) 183 } 184 case 4<<3 | byte(amino.Typ3_Varint): 185 if m.CompressType, err = amino.DecodeIntUpdateBytes(&data); err != nil { 186 return err 187 } 188 case 5<<3 | byte(amino.Typ3_ByteLength): 189 m.From = string(subData) 190 default: 191 return fmt.Errorf("unexpect pb key %d", pbk) 192 } 193 } 194 } 195 196 if len(data) != 0 { 197 return fmt.Errorf("unexpect data remain %X", data) 198 } 199 200 return nil 201 } 202 203 type DeltaPayload struct { 204 ABCIRsp []byte 205 DeltasBytes []byte 206 WatchBytes []byte 207 WasmWatchBytes []byte 208 } 209 210 func (payload *DeltaPayload) AminoSize(_ *amino.Codec) int { 211 var size int 212 // field 1 213 if len(payload.ABCIRsp) != 0 { 214 size += 1 + amino.ByteSliceSize(payload.ABCIRsp) 215 } 216 // field 2 217 if len(payload.DeltasBytes) != 0 { 218 size += 1 + amino.ByteSliceSize(payload.DeltasBytes) 219 } 220 // field 3 221 if len(payload.WatchBytes) != 0 { 222 size += 1 + amino.ByteSliceSize(payload.WatchBytes) 223 } 224 // field 4 225 if len(payload.WasmWatchBytes) != 0 { 226 size += 1 + amino.ByteSliceSize(payload.WasmWatchBytes) 227 } 228 return size 229 } 230 231 func (payload *DeltaPayload) MarshalToAmino(cdc *amino.Codec) ([]byte, error) { 232 var buf bytes.Buffer 233 buf.Grow(payload.AminoSize(cdc)) 234 err := payload.MarshalAminoTo(cdc, &buf) 235 if err != nil { 236 return nil, err 237 } 238 return buf.Bytes(), nil 239 } 240 241 func (payload *DeltaPayload) MarshalAminoTo(_ *amino.Codec, buf *bytes.Buffer) error { 242 // field 1 243 if len(payload.ABCIRsp) != 0 { 244 const pbKey = 1<<3 | 2 245 if err := amino.EncodeByteSliceWithKeyToBuffer(buf, payload.ABCIRsp, pbKey); err != nil { 246 return err 247 } 248 } 249 // field 2 250 if len(payload.DeltasBytes) != 0 { 251 const pbKey = 2<<3 | 2 252 if err := amino.EncodeByteSliceWithKeyToBuffer(buf, payload.DeltasBytes, pbKey); err != nil { 253 return err 254 } 255 } 256 // field 3 257 if len(payload.WatchBytes) != 0 { 258 const pbKey = 3<<3 | 2 259 if err := amino.EncodeByteSliceWithKeyToBuffer(buf, payload.WatchBytes, pbKey); err != nil { 260 return err 261 } 262 } 263 // field 4 264 if len(payload.WasmWatchBytes) != 0 { 265 const pbKey = 4<<3 | 2 266 if err := amino.EncodeByteSliceWithKeyToBuffer(buf, payload.WasmWatchBytes, pbKey); err != nil { 267 return err 268 } 269 } 270 return nil 271 } 272 273 func (payload *DeltaPayload) UnmarshalFromAmino(_ *amino.Codec, data []byte) error { 274 const fieldCount = 4 275 var currentField int 276 var currentType amino.Typ3 277 var err error 278 279 for cur := 1; cur <= fieldCount; cur++ { 280 if len(data) != 0 && (currentField == 0 || currentField < cur) { 281 var nextField int 282 if nextField, currentType, err = amino.ParseProtoPosAndTypeMustOneByte(data[0]); err != nil { 283 return err 284 } 285 if nextField < currentField { 286 return fmt.Errorf("next field should greater than %d, got %d", currentField, nextField) 287 } else { 288 currentField = nextField 289 } 290 } 291 292 if len(data) == 0 || currentField != cur { 293 switch cur { 294 case 1: 295 payload.ABCIRsp = nil 296 case 2: 297 payload.DeltasBytes = nil 298 case 3: 299 payload.WatchBytes = nil 300 case 4: 301 payload.WasmWatchBytes = nil 302 default: 303 return fmt.Errorf("unexpect feild num %d", cur) 304 } 305 } else { 306 pbk := data[0] 307 data = data[1:] 308 var subData []byte 309 if currentType == amino.Typ3_ByteLength { 310 if subData, err = amino.DecodeByteSliceWithoutCopy(&data); err != nil { 311 return err 312 } 313 } 314 switch pbk { 315 case 1<<3 | byte(amino.Typ3_ByteLength): 316 if len(subData) != 0 { 317 payload.ABCIRsp = make([]byte, len(subData)) 318 copy(payload.ABCIRsp, subData) 319 } else { 320 payload.ABCIRsp = nil 321 } 322 case 2<<3 | byte(amino.Typ3_ByteLength): 323 if len(subData) != 0 { 324 payload.DeltasBytes = make([]byte, len(subData)) 325 copy(payload.DeltasBytes, subData) 326 } else { 327 payload.DeltasBytes = nil 328 } 329 case 3<<3 | byte(amino.Typ3_ByteLength): 330 if len(subData) != 0 { 331 payload.WatchBytes = make([]byte, len(subData)) 332 copy(payload.WatchBytes, subData) 333 } else { 334 payload.WatchBytes = nil 335 } 336 case 4<<3 | byte(amino.Typ3_ByteLength): 337 if len(subData) != 0 { 338 payload.WasmWatchBytes = make([]byte, len(subData)) 339 copy(payload.WasmWatchBytes, subData) 340 } else { 341 payload.WasmWatchBytes = nil 342 } 343 default: 344 return fmt.Errorf("unexpect pb key %d", pbk) 345 } 346 } 347 } 348 349 if len(data) != 0 { 350 return fmt.Errorf("unexpect data remain %X", data) 351 } 352 353 return nil 354 } 355 356 // Deltas defines the ABCIResponse and state delta 357 type Deltas struct { 358 Height int64 359 Payload DeltaPayload 360 CompressType int 361 CompressFlag int 362 From string 363 364 marshalElapsed time.Duration 365 compressElapsed time.Duration 366 hashElapsed time.Duration 367 } 368 369 // Size returns size of the deltas in bytes. 370 func (d *Deltas) Size() int { 371 return len(d.ABCIRsp()) + len(d.DeltasBytes()) + len(d.WatchBytes()) 372 } 373 func (d *Deltas) ABCIRsp() []byte { 374 return d.Payload.ABCIRsp 375 } 376 377 func (d *Deltas) DeltasBytes() []byte { 378 return d.Payload.DeltasBytes 379 } 380 381 func (d *Deltas) WatchBytes() []byte { 382 return d.Payload.WatchBytes 383 } 384 385 func (d *Deltas) WasmWatchBytes() []byte { 386 return d.Payload.WasmWatchBytes 387 } 388 389 func (d *Deltas) MarshalOrUnmarshalElapsed() time.Duration { 390 return d.marshalElapsed 391 } 392 func (d *Deltas) CompressOrUncompressElapsed() time.Duration { 393 return d.compressElapsed 394 } 395 func (d *Deltas) HashElapsed() time.Duration { 396 return d.hashElapsed 397 } 398 399 // Marshal returns the amino encoding. 400 func (d *Deltas) Marshal() ([]byte, error) { 401 t0 := time.Now() 402 403 // marshal to payload bytes 404 payload, err := d.Payload.MarshalToAmino(cdc) 405 if err != nil { 406 return nil, err 407 } 408 409 t1 := time.Now() 410 // calc payload hash 411 payloadHash := tmhash.Sum(payload) 412 413 // compress 414 t2 := time.Now() 415 payload, err = compress.Compress(d.CompressType, d.CompressFlag, payload) 416 if err != nil { 417 return nil, err 418 } 419 t3 := time.Now() 420 421 dt := &DeltasMessage{ 422 Metadata: payload, 423 Height: d.Height, 424 CompressType: d.CompressType, 425 MetadataHash: payloadHash, 426 From: d.From, 427 } 428 429 // marshal to upload bytes 430 res, err := dt.MarshalToAmino(cdc) 431 t4 := time.Now() 432 433 d.hashElapsed = t2.Sub(t1) 434 d.compressElapsed = t3.Sub(t2) 435 d.marshalElapsed = t4.Sub(t0) - d.compressElapsed - d.hashElapsed 436 437 return res, err 438 } 439 440 // Unmarshal deserializes from amino encoded form. 441 func (d *Deltas) Unmarshal(bs []byte) error { 442 t0 := time.Now() 443 // unmarshal to DeltasMessage 444 msg := &DeltasMessage{} 445 err := msg.UnmarshalFromAmino(cdc, bs) 446 if err != nil { 447 return err 448 } 449 450 t1 := time.Now() 451 // uncompress 452 d.CompressType = msg.CompressType 453 msg.Metadata, err = compress.UnCompress(d.CompressType, msg.Metadata) 454 if err != nil { 455 return err 456 } 457 458 t2 := time.Now() 459 // calc payload hash 460 payloadHash := tmhash.Sum(msg.Metadata) 461 if bytes.Compare(payloadHash, msg.MetadataHash) != 0 { 462 return fmt.Errorf("metadata hash is different") 463 } 464 t3 := time.Now() 465 466 err = d.Payload.UnmarshalFromAmino(cdc, msg.Metadata) 467 t4 := time.Now() 468 469 d.Height = msg.Height 470 d.From = msg.From 471 472 d.compressElapsed = t2.Sub(t1) 473 d.hashElapsed = t3.Sub(t2) 474 d.marshalElapsed = t4.Sub(t0) - d.compressElapsed - d.hashElapsed 475 return err 476 } 477 478 func (d *Deltas) String() string { 479 return fmt.Sprintf("height<%d>, size<%d>, from<%s>", 480 d.Height, 481 d.Size(), 482 d.From, 483 ) 484 } 485 486 func (dds *Deltas) Validate(height int64) bool { 487 if dds.Height != height || 488 len(dds.ABCIRsp()) == 0 || 489 len(dds.DeltasBytes()) == 0 { 490 return false 491 } 492 if FastQuery { 493 if len(dds.WatchBytes()) == 0 { 494 return false 495 } 496 } 497 return true 498 }