Skip to content

Commit 89e51a3

Browse files
committed
Add funcs to check availablility of CBOR tag nums
This commit: * Adds IsCBORTagNumberRangeAvailable() * Adds ReservedCBORTagNumberRange() * Reserves CBOR tag numbers [240, 255] for atree internal use IsCBORTagNumberRangeAvailable() checks if specified range of CBOR tag numbers can be used to encode elements managed by atree containers. ReservedCBORTagNumberRange() returns minTagNum and maxTagNum of the range of CBOR tag numbers reserved by atree. Currently, Atree and Cadence uses CBOR tag numbers: * Atree: 246 to 255 * Cadence: 128 to 230 to encode internal Cadence values This commit reserves CBOR tag numbers [240, 255] for atree internal use. Applications must use unreserved CBOR tag numbers to encode elements managed by atree containers. When a new tag number is needed, Atree will use higher tag number first from its reserved range. By contrast, Cadence will use lower tag numbers first from its own (different) reserved range. This allows Atree and Cadence more flexibility in case we need to revisit the allocation of adjacent unused ranges for Atree and Cadence.
1 parent bb0f1aa commit 89e51a3

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

storable.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,28 @@ func hasPointer(storable Storable) bool {
7373
const (
7474
// WARNING: tag numbers defined in here in github.com/onflow/atree
7575
// MUST not overlap with tag numbers used by Cadence internal value encoding.
76-
// As of Oct. 2, 2023, Cadence uses tag numbers from 128 to 224.
76+
// As of Aug. 14, 2024, Cadence uses tag numbers from 128 to 230.
7777
// See runtime/interpreter/encode.go at github.com/onflow/cadence.
7878

79+
// Atree reserves CBOR tag numbers [240, 255] for internal use.
80+
// Applications must use non-overlapping CBOR tag numbers to encode
81+
// elements managed by atree containers.
82+
minInternalCBORTagNumber = 240
83+
maxInternalCBORTagNumber = 255
84+
85+
// Reserved CBOR tag numbers for atree internal use.
86+
87+
// Replace _ when new tag number is needed (use higher tag numbers first).
88+
// Atree will use higher tag numbers first because Cadence will use lower tag numbers first.
89+
// This approach allows more flexibility in case we need to revisit ranges used by Atree and Cadence.
90+
91+
_ = 240
92+
_ = 241
93+
_ = 242
94+
_ = 243
95+
_ = 244
96+
_ = 245
97+
7998
CBORTagTypeInfoRef = 246
8099

81100
CBORTagInlinedArrayExtraData = 247
@@ -92,6 +111,22 @@ const (
92111
CBORTagSlabID = 255
93112
)
94113

114+
// IsCBORTagNumberRangeAvailable returns true if the specified range is not reserved for internal use by atree.
115+
// Applications must only use available (unreserved) CBOR tag numbers to encode elements in atree managed containers.
116+
func IsCBORTagNumberRangeAvailable(minTagNum, maxTagNum uint64) (bool, error) {
117+
if minTagNum > maxTagNum {
118+
return false, NewUserError(fmt.Errorf("min CBOR tag number %d must be <= max CBOR tag number %d", minTagNum, maxTagNum))
119+
}
120+
121+
return maxTagNum < minInternalCBORTagNumber || minTagNum > maxInternalCBORTagNumber, nil
122+
}
123+
124+
// ReservedCBORTagNumberRange returns minTagNum and maxTagNum of the range of CBOR tag numbers
125+
// reserved for internal use by atree.
126+
func ReservedCBORTagNumberRange() (minTagNum, maxTagNum uint64) {
127+
return minInternalCBORTagNumber, maxInternalCBORTagNumber
128+
}
129+
95130
type SlabIDStorable SlabID
96131

97132
var _ ContainerStorable = SlabIDStorable{}

storable_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ import (
2222
"encoding/binary"
2323
"fmt"
2424
"math"
25+
"testing"
2526

2627
"github.com/fxamacker/cbor/v2"
28+
"github.com/stretchr/testify/require"
2729
)
2830

2931
// This file contains value implementations for testing purposes
@@ -37,6 +39,64 @@ const (
3739
cborTagHashableMap = 166
3840
)
3941

42+
func TestIsCBORTagNumberRangeAvailable(t *testing.T) {
43+
t.Run("error", func(t *testing.T) {
44+
_, err := IsCBORTagNumberRangeAvailable(maxInternalCBORTagNumber, minInternalCBORTagNumber)
45+
var userError *UserError
46+
require.ErrorAs(t, err, &userError)
47+
})
48+
49+
t.Run("identical", func(t *testing.T) {
50+
available, err := IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber, maxInternalCBORTagNumber)
51+
require.NoError(t, err)
52+
require.False(t, available)
53+
})
54+
55+
t.Run("subrange", func(t *testing.T) {
56+
available, err := IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber, maxInternalCBORTagNumber-1)
57+
require.NoError(t, err)
58+
require.False(t, available)
59+
60+
available, err = IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber+1, maxInternalCBORTagNumber)
61+
require.NoError(t, err)
62+
require.False(t, available)
63+
})
64+
65+
t.Run("partial overlap", func(t *testing.T) {
66+
available, err := IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber-1, maxInternalCBORTagNumber-1)
67+
require.NoError(t, err)
68+
require.False(t, available)
69+
70+
available, err = IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber+1, maxInternalCBORTagNumber+1)
71+
require.NoError(t, err)
72+
require.False(t, available)
73+
})
74+
75+
t.Run("non-overlap", func(t *testing.T) {
76+
available, err := IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber-10, minInternalCBORTagNumber-1)
77+
require.NoError(t, err)
78+
require.True(t, available)
79+
80+
available, err = IsCBORTagNumberRangeAvailable(minInternalCBORTagNumber-1, minInternalCBORTagNumber-1)
81+
require.NoError(t, err)
82+
require.True(t, available)
83+
84+
available, err = IsCBORTagNumberRangeAvailable(maxInternalCBORTagNumber+1, maxInternalCBORTagNumber+10)
85+
require.NoError(t, err)
86+
require.True(t, available)
87+
88+
available, err = IsCBORTagNumberRangeAvailable(maxInternalCBORTagNumber+10, maxInternalCBORTagNumber+10)
89+
require.NoError(t, err)
90+
require.True(t, available)
91+
})
92+
}
93+
94+
func TestReservedCBORTagNumberRange(t *testing.T) {
95+
minTagNum, maxTagNum := ReservedCBORTagNumberRange()
96+
require.Equal(t, uint64(minInternalCBORTagNumber), minTagNum)
97+
require.Equal(t, uint64(maxInternalCBORTagNumber), maxTagNum)
98+
}
99+
40100
type HashableValue interface {
41101
Value
42102
HashInput(scratch []byte) ([]byte, error)

0 commit comments

Comments
 (0)