github.com/onflow/atree@v0.6.0/cmd/stress/storable.go (about) 1 /* 2 * Atree - Scalable Arrays and Ordered Maps 3 * 4 * Copyright 2021 Dapper Labs, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package main 20 21 import ( 22 "encoding/binary" 23 "fmt" 24 "math" 25 26 "github.com/onflow/atree" 27 28 "github.com/fxamacker/cbor/v2" 29 ) 30 31 // This file is mostly from github.com/onflow/atree/storable_test.go 32 // This file contains value implementations for testing purposes. 33 34 const ( 35 cborTagUInt8Value = 161 36 cborTagUInt16Value = 162 37 cborTagUInt32Value = 163 38 cborTagUInt64Value = 164 39 ) 40 41 type Uint8Value uint8 42 43 var _ atree.Value = Uint8Value(0) 44 var _ atree.Storable = Uint8Value(0) 45 46 func (v Uint8Value) ChildStorables() []atree.Storable { 47 return nil 48 } 49 50 func (v Uint8Value) StoredValue(_ atree.SlabStorage) (atree.Value, error) { 51 return v, nil 52 } 53 54 func (v Uint8Value) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { 55 return v, nil 56 } 57 58 // Encode encodes UInt8Value as 59 // 60 // cbor.Tag{ 61 // Number: cborTagUInt8Value, 62 // Content: uint8(v), 63 // } 64 func (v Uint8Value) Encode(enc *atree.Encoder) error { 65 err := enc.CBOR.EncodeRawBytes([]byte{ 66 // tag number 67 0xd8, cborTagUInt8Value, 68 }) 69 if err != nil { 70 return err 71 } 72 return enc.CBOR.EncodeUint8(uint8(v)) 73 } 74 75 func (v Uint8Value) getHashInput(scratch []byte) ([]byte, error) { 76 77 const cborTypePositiveInt = 0x00 78 79 buf := scratch 80 if len(scratch) < 4 { 81 buf = make([]byte, 4) 82 } 83 84 buf[0], buf[1] = 0xd8, cborTagUInt8Value // Tag number 85 86 if v <= 23 { 87 buf[2] = cborTypePositiveInt | byte(v) 88 return buf[:3], nil 89 } 90 91 buf[2] = cborTypePositiveInt | byte(24) 92 buf[3] = byte(v) 93 return buf[:4], nil 94 } 95 96 // TODO: cache size 97 func (v Uint8Value) ByteSize() uint32 { 98 // tag number (2 bytes) + encoded content 99 return 2 + atree.GetUintCBORSize(uint64(v)) 100 } 101 102 func (v Uint8Value) String() string { 103 return fmt.Sprintf("%d", uint8(v)) 104 } 105 106 type Uint16Value uint16 107 108 var _ atree.Value = Uint16Value(0) 109 var _ atree.Storable = Uint16Value(0) 110 111 func (v Uint16Value) ChildStorables() []atree.Storable { 112 return nil 113 } 114 115 func (v Uint16Value) StoredValue(_ atree.SlabStorage) (atree.Value, error) { 116 return v, nil 117 } 118 119 func (v Uint16Value) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { 120 return v, nil 121 } 122 123 func (v Uint16Value) Encode(enc *atree.Encoder) error { 124 err := enc.CBOR.EncodeRawBytes([]byte{ 125 // tag number 126 0xd8, cborTagUInt16Value, 127 }) 128 if err != nil { 129 return err 130 } 131 return enc.CBOR.EncodeUint16(uint16(v)) 132 } 133 134 func (v Uint16Value) getHashInput(scratch []byte) ([]byte, error) { 135 const cborTypePositiveInt = 0x00 136 137 buf := scratch 138 if len(buf) < 8 { 139 buf = make([]byte, 8) 140 } 141 142 buf[0], buf[1] = 0xd8, cborTagUInt16Value // Tag number 143 144 if v <= 23 { 145 buf[2] = cborTypePositiveInt | byte(v) 146 return buf[:3], nil 147 } 148 149 if v <= math.MaxUint8 { 150 buf[2] = cborTypePositiveInt | byte(24) 151 buf[3] = byte(v) 152 return buf[:4], nil 153 } 154 155 buf[2] = cborTypePositiveInt | byte(25) 156 binary.BigEndian.PutUint16(buf[3:], uint16(v)) 157 return buf[:5], nil 158 } 159 160 // TODO: cache size 161 func (v Uint16Value) ByteSize() uint32 { 162 // tag number (2 bytes) + encoded content 163 return 2 + atree.GetUintCBORSize(uint64(v)) 164 } 165 166 func (v Uint16Value) String() string { 167 return fmt.Sprintf("%d", uint16(v)) 168 } 169 170 type Uint32Value uint32 171 172 var _ atree.Value = Uint32Value(0) 173 var _ atree.Storable = Uint32Value(0) 174 175 func (v Uint32Value) ChildStorables() []atree.Storable { 176 return nil 177 } 178 179 func (v Uint32Value) StoredValue(_ atree.SlabStorage) (atree.Value, error) { 180 return v, nil 181 } 182 183 func (v Uint32Value) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { 184 return v, nil 185 } 186 187 // Encode encodes UInt32Value as 188 // 189 // cbor.Tag{ 190 // Number: cborTagUInt32Value, 191 // Content: uint32(v), 192 // } 193 func (v Uint32Value) Encode(enc *atree.Encoder) error { 194 err := enc.CBOR.EncodeRawBytes([]byte{ 195 // tag number 196 0xd8, cborTagUInt32Value, 197 }) 198 if err != nil { 199 return err 200 } 201 return enc.CBOR.EncodeUint32(uint32(v)) 202 } 203 204 func (v Uint32Value) getHashInput(scratch []byte) ([]byte, error) { 205 206 const cborTypePositiveInt = 0x00 207 208 buf := scratch 209 if len(buf) < 8 { 210 buf = make([]byte, 8) 211 } 212 213 buf[0], buf[1] = 0xd8, cborTagUInt32Value // Tag number 214 215 if v <= 23 { 216 buf[2] = cborTypePositiveInt | byte(v) 217 return buf[:3], nil 218 } 219 220 if v <= math.MaxUint8 { 221 buf[2] = cborTypePositiveInt | byte(24) 222 buf[3] = byte(v) 223 return buf[:4], nil 224 } 225 226 if v <= math.MaxUint16 { 227 buf[2] = cborTypePositiveInt | byte(25) 228 binary.BigEndian.PutUint16(buf[3:], uint16(v)) 229 return buf[:5], nil 230 } 231 232 buf[2] = cborTypePositiveInt | byte(26) 233 binary.BigEndian.PutUint32(buf[3:], uint32(v)) 234 return buf[:7], nil 235 } 236 237 // TODO: cache size 238 func (v Uint32Value) ByteSize() uint32 { 239 // tag number (2 bytes) + encoded content 240 return 2 + atree.GetUintCBORSize(uint64(v)) 241 } 242 243 func (v Uint32Value) String() string { 244 return fmt.Sprintf("%d", uint32(v)) 245 } 246 247 type Uint64Value uint64 248 249 var _ atree.Value = Uint64Value(0) 250 var _ atree.Storable = Uint64Value(0) 251 252 func (v Uint64Value) ChildStorables() []atree.Storable { 253 return nil 254 } 255 256 func (v Uint64Value) StoredValue(_ atree.SlabStorage) (atree.Value, error) { 257 return v, nil 258 } 259 260 func (v Uint64Value) Storable(_ atree.SlabStorage, _ atree.Address, _ uint64) (atree.Storable, error) { 261 return v, nil 262 } 263 264 // Encode encodes UInt64Value as 265 // 266 // cbor.Tag{ 267 // Number: cborTagUInt64Value, 268 // Content: uint64(v), 269 // } 270 func (v Uint64Value) Encode(enc *atree.Encoder) error { 271 err := enc.CBOR.EncodeRawBytes([]byte{ 272 // tag number 273 0xd8, cborTagUInt64Value, 274 }) 275 if err != nil { 276 return err 277 } 278 return enc.CBOR.EncodeUint64(uint64(v)) 279 } 280 281 func (v Uint64Value) getHashInput(scratch []byte) ([]byte, error) { 282 const cborTypePositiveInt = 0x00 283 284 buf := scratch 285 if len(buf) < 16 { 286 buf = make([]byte, 16) 287 } 288 289 buf[0], buf[1] = 0xd8, cborTagUInt64Value // Tag number 290 291 if v <= 23 { 292 buf[2] = cborTypePositiveInt | byte(v) 293 return buf[:3], nil 294 } 295 296 if v <= math.MaxUint8 { 297 buf[2] = cborTypePositiveInt | byte(24) 298 buf[3] = byte(v) 299 return buf[:4], nil 300 } 301 302 if v <= math.MaxUint16 { 303 buf[2] = cborTypePositiveInt | byte(25) 304 binary.BigEndian.PutUint16(buf[3:], uint16(v)) 305 return buf[:5], nil 306 } 307 308 if v <= math.MaxUint32 { 309 buf[2] = cborTypePositiveInt | byte(26) 310 binary.BigEndian.PutUint32(buf[3:], uint32(v)) 311 return buf[:7], nil 312 } 313 314 buf[2] = cborTypePositiveInt | byte(27) 315 binary.BigEndian.PutUint64(buf[3:], uint64(v)) 316 return buf[:11], nil 317 } 318 319 // TODO: cache size 320 func (v Uint64Value) ByteSize() uint32 { 321 // tag number (2 bytes) + encoded content 322 return 2 + atree.GetUintCBORSize(uint64(v)) 323 } 324 325 func (v Uint64Value) String() string { 326 return fmt.Sprintf("%d", uint64(v)) 327 } 328 329 type StringValue struct { 330 str string 331 size uint32 332 } 333 334 var _ atree.Value = &StringValue{} 335 var _ atree.Storable = &StringValue{} 336 337 func NewStringValue(s string) StringValue { 338 size := atree.GetUintCBORSize(uint64(len(s))) + uint32(len(s)) 339 return StringValue{str: s, size: size} 340 } 341 342 func (v StringValue) ChildStorables() []atree.Storable { 343 return nil 344 } 345 346 func (v StringValue) StoredValue(_ atree.SlabStorage) (atree.Value, error) { 347 return v, nil 348 } 349 350 func (v StringValue) Storable(storage atree.SlabStorage, address atree.Address, maxInlineSize uint64) (atree.Storable, error) { 351 if uint64(v.ByteSize()) > maxInlineSize { 352 353 // Create StorableSlab 354 id, err := storage.GenerateStorageID(address) 355 if err != nil { 356 return nil, err 357 } 358 359 slab := &atree.StorableSlab{ 360 StorageID: id, 361 Storable: v, 362 } 363 364 // Store StorableSlab in storage 365 err = storage.Store(id, slab) 366 if err != nil { 367 return nil, err 368 } 369 370 // Return storage id as storable 371 return atree.StorageIDStorable(id), nil 372 } 373 374 return v, nil 375 } 376 377 func (v StringValue) Encode(enc *atree.Encoder) error { 378 return enc.CBOR.EncodeString(v.str) 379 } 380 381 func (v StringValue) getHashInput(scratch []byte) ([]byte, error) { 382 383 const cborTypeTextString = 0x60 384 385 buf := scratch 386 if uint32(len(buf)) < v.size { 387 buf = make([]byte, v.size) 388 } else { 389 buf = buf[:v.size] 390 } 391 392 slen := len(v.str) 393 394 if slen <= 23 { 395 buf[0] = cborTypeTextString | byte(slen) 396 copy(buf[1:], v.str) 397 return buf, nil 398 } 399 400 if slen <= math.MaxUint8 { 401 buf[0] = cborTypeTextString | byte(24) 402 buf[1] = byte(slen) 403 copy(buf[2:], v.str) 404 return buf, nil 405 } 406 407 if slen <= math.MaxUint16 { 408 buf[0] = cborTypeTextString | byte(25) 409 binary.BigEndian.PutUint16(buf[1:], uint16(slen)) 410 copy(buf[3:], v.str) 411 return buf, nil 412 } 413 414 if slen <= math.MaxUint32 { 415 buf[0] = cborTypeTextString | byte(26) 416 binary.BigEndian.PutUint32(buf[1:], uint32(slen)) 417 copy(buf[5:], v.str) 418 return buf, nil 419 } 420 421 buf[0] = cborTypeTextString | byte(27) 422 binary.BigEndian.PutUint64(buf[1:], uint64(slen)) 423 copy(buf[9:], v.str) 424 return buf, nil 425 } 426 427 func (v StringValue) ByteSize() uint32 { 428 return v.size 429 } 430 431 func (v StringValue) String() string { 432 return v.str 433 } 434 435 func decodeStorable(dec *cbor.StreamDecoder, _ atree.StorageID) (atree.Storable, error) { 436 t, err := dec.NextType() 437 if err != nil { 438 return nil, err 439 } 440 441 switch t { 442 case cbor.TextStringType: 443 s, err := dec.DecodeString() 444 if err != nil { 445 return nil, err 446 } 447 return NewStringValue(s), nil 448 449 case cbor.TagType: 450 tagNumber, err := dec.DecodeTagNumber() 451 if err != nil { 452 return nil, err 453 } 454 455 switch tagNumber { 456 457 case atree.CBORTagStorageID: 458 return atree.DecodeStorageIDStorable(dec) 459 460 case cborTagUInt8Value: 461 n, err := dec.DecodeUint64() 462 if err != nil { 463 return nil, err 464 } 465 if n > math.MaxUint8 { 466 return nil, fmt.Errorf("invalid data, got %d, expected max %d", n, math.MaxUint8) 467 } 468 return Uint8Value(n), nil 469 470 case cborTagUInt16Value: 471 n, err := dec.DecodeUint64() 472 if err != nil { 473 return nil, err 474 } 475 if n > math.MaxUint16 { 476 return nil, fmt.Errorf("invalid data, got %d, expected max %d", n, math.MaxUint16) 477 } 478 return Uint16Value(n), nil 479 480 case cborTagUInt32Value: 481 n, err := dec.DecodeUint64() 482 if err != nil { 483 return nil, err 484 } 485 if n > math.MaxUint32 { 486 return nil, fmt.Errorf("invalid data, got %d, expected max %d", n, math.MaxUint32) 487 } 488 return Uint32Value(n), nil 489 490 case cborTagUInt64Value: 491 n, err := dec.DecodeUint64() 492 if err != nil { 493 return nil, err 494 } 495 return Uint64Value(n), nil 496 497 default: 498 return nil, fmt.Errorf("invalid tag number %d", tagNumber) 499 } 500 501 default: 502 return nil, fmt.Errorf("invalid cbor type %s for storable", t) 503 } 504 } 505 506 func compare(storage atree.SlabStorage, value atree.Value, storable atree.Storable) (bool, error) { 507 switch v := value.(type) { 508 509 case Uint8Value: 510 other, ok := storable.(Uint8Value) 511 if !ok { 512 return false, nil 513 } 514 return uint8(other) == uint8(v), nil 515 516 case Uint16Value: 517 other, ok := storable.(Uint16Value) 518 if !ok { 519 return false, nil 520 } 521 return uint16(other) == uint16(v), nil 522 523 case Uint32Value: 524 other, ok := storable.(Uint32Value) 525 if !ok { 526 return false, nil 527 } 528 return uint32(other) == uint32(v), nil 529 530 case Uint64Value: 531 other, ok := storable.(Uint64Value) 532 if !ok { 533 return false, nil 534 } 535 return uint64(other) == uint64(v), nil 536 537 case StringValue: 538 other, ok := storable.(StringValue) 539 if ok { 540 return other.str == v.str, nil 541 } 542 543 // Retrieve value from storage 544 otherValue, err := storable.StoredValue(storage) 545 if err != nil { 546 return false, err 547 } 548 other, ok = otherValue.(StringValue) 549 if ok { 550 return other.str == v.str, nil 551 } 552 553 return false, nil 554 } 555 556 return false, fmt.Errorf("value %T not supported for comparison", value) 557 } 558 559 func hashInputProvider(value atree.Value, buffer []byte) ([]byte, error) { 560 switch v := value.(type) { 561 562 case Uint8Value: 563 return v.getHashInput(buffer) 564 565 case Uint16Value: 566 return v.getHashInput(buffer) 567 568 case Uint32Value: 569 return v.getHashInput(buffer) 570 571 case Uint64Value: 572 return v.getHashInput(buffer) 573 574 case StringValue: 575 return v.getHashInput(buffer) 576 } 577 578 return nil, fmt.Errorf("value %T not supported for hash input", value) 579 }