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  }