Skip to content

Commit ef83e8f

Browse files
committed
initial commit
0 parents  commit ef83e8f

27 files changed

+3952
-0
lines changed

.gas-snapshot

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
ArrayTest:test_decodeEmptyArray() (gas: 3443)
2+
ArrayTest:test_decodeLargeArray() (gas: 3486)
3+
ArrayTest:test_decodeMixedArray() (gas: 6654)
4+
ArrayTest:test_decodeNestedArray() (gas: 7376)
5+
ArrayTest:test_decodeSingleElementArray() (gas: 4237)
6+
BytesTest:testFail_Bytes32_long() (gas: 782)
7+
BytesTest:testFail_Bytes32_parameter() (gas: 374)
8+
BytesTest:testFail_invalidBytes() (gas: 1041)
9+
BytesTest:testFail_skipBytes() (gas: 519)
10+
BytesTest:test_Bytes32_short() (gas: 4288)
11+
BytesTest:test_decodeEmptyBytes() (gas: 3877)
12+
BytesTest:test_decodeLongBytes() (gas: 3971)
13+
BytesTest:test_decodeMediumBytes() (gas: 1094)
14+
BytesTest:test_decodeShortBytes() (gas: 3964)
15+
BytesTest:test_skipBytes() (gas: 786)
16+
ComparisonTest:test_decodeArrayU8_CBORDecoder() (gas: 5338)
17+
ComparisonTest:test_decodeArrayU8_ReadCbor() (gas: 2359)
18+
ComparisonTest:test_decodeFalse_CBORDecoder() (gas: 927)
19+
ComparisonTest:test_decodeFalse_ReadCbor() (gas: 440)
20+
ComparisonTest:test_decodeFixedArray_CBORDecoder() (gas: 9454)
21+
ComparisonTest:test_decodeFixedArray_ReadCbor() (gas: 4649)
22+
ComparisonTest:test_decodeInteger_CBORDecoder() (gas: 895)
23+
ComparisonTest:test_decodeInteger_ReadCbor() (gas: 560)
24+
ComparisonTest:test_decodeNull_CBORDecoder() (gas: 399)
25+
ComparisonTest:test_decodeNull_ReadCbor() (gas: 241)
26+
ComparisonTest:test_decodeStringWithWeirdChar_CBORDecoder() (gas: 2377)
27+
ComparisonTest:test_decodeStringWithWeirdChar_ReadCbor() (gas: 1129)
28+
ComparisonTest:test_decodeString_CBORDecoder() (gas: 3902)
29+
ComparisonTest:test_decodeString_ReadCbor() (gas: 1202)
30+
ComparisonTest:test_decodeTrue_CBORDecoder() (gas: 948)
31+
ComparisonTest:test_decodeTrue_ReadCbor() (gas: 498)
32+
HeaderTest:testFail_header32_badu8() (gas: 611)
33+
HeaderTest:testFail_header32_u64() (gas: 617)
34+
HeaderTest:testFail_header8_expectMajor() (gas: 500)
35+
HeaderTest:testFail_header_badext() (gas: 702)
36+
HeaderTest:testFail_header_expectMajor() (gas: 475)
37+
HeaderTest:testFail_header_expectMinor_failmajor() (gas: 502)
38+
HeaderTest:testFail_parseArg_unsupportedMinor(uint8) (runs: 256, μ: 3993, ~: 3993)
39+
HeaderTest:test_header() (gas: 4277)
40+
HeaderTest:test_header32_u16() (gas: 3647)
41+
HeaderTest:test_header32_u32() (gas: 3621)
42+
MapTest:test_decodeEmptyMap() (gas: 544)
43+
MapTest:test_decodeNestedMap() (gas: 4413)
44+
MapTest:test_decodeSingleKeyMap() (gas: 6000)
45+
MapTest:test_deeplyNestedStructure() (gas: 10313)
46+
NIntTest:testFail_badInt() (gas: 455)
47+
NIntTest:testFail_invalidNInt8() (gas: 674)
48+
NIntTest:testFail_notNInt8() (gas: 581)
49+
NIntTest:testFail_outOfBoundsNInt16() (gas: 545)
50+
NIntTest:test_decodeLongNInt8() (gas: 3660)
51+
NIntTest:test_decodeNInt16() (gas: 3814)
52+
NIntTest:test_decodeNInt32() (gas: 3797)
53+
NIntTest:test_decodeNInt64() (gas: 3834)
54+
NIntTest:test_decodeNInt8() (gas: 3681)
55+
NIntTest:test_decodeShortNInt8() (gas: 3584)
56+
NIntTest:test_decodeSmallNInts() (gas: 4435)
57+
PeekTest:test_isArray_false() (gas: 3184)
58+
PeekTest:test_isArray_true() (gas: 3162)
59+
PeekTest:test_isBool_false() (gas: 3161)
60+
PeekTest:test_isBool_true() (gas: 3601)
61+
PeekTest:test_isBytes_false() (gas: 3204)
62+
PeekTest:test_isBytes_true() (gas: 3161)
63+
PeekTest:test_isInt_false() (gas: 3182)
64+
PeekTest:test_isInt_true() (gas: 3692)
65+
PeekTest:test_isMap_false() (gas: 3160)
66+
PeekTest:test_isMap_true() (gas: 3184)
67+
PeekTest:test_isNInt_false() (gas: 3222)
68+
PeekTest:test_isNInt_true() (gas: 3162)
69+
PeekTest:test_isNull_false() (gas: 3246)
70+
PeekTest:test_isNull_true() (gas: 3184)
71+
PeekTest:test_isString_false() (gas: 3184)
72+
PeekTest:test_isString_true() (gas: 3163)
73+
PeekTest:test_isTag_expect_badminor() (gas: 3726)
74+
PeekTest:test_isTag_expect_false() (gas: 3338)
75+
PeekTest:test_isTag_expect_rand_16(uint16) (runs: 256, μ: 3623, ~: 3623)
76+
PeekTest:test_isTag_expect_rand_64(uint32) (runs: 256, μ: 3634, ~: 3634)
77+
PeekTest:test_isTag_expect_rand_64(uint64) (runs: 256, μ: 3607, ~: 3607)
78+
PeekTest:test_isTag_expect_true() (gas: 3324)
79+
PeekTest:test_isTag_false() (gas: 3182)
80+
PeekTest:test_isTag_false_expect() (gas: 3286)
81+
PeekTest:test_isTag_true() (gas: 3183)
82+
PeekTest:test_isUInt_false() (gas: 3205)
83+
PeekTest:test_isUInt_true() (gas: 3231)
84+
PeekTest:test_isUndefined_false() (gas: 3245)
85+
PeekTest:test_isUndefined_true() (gas: 3164)
86+
RangeTest:testFail_requireComplete() (gas: 370)
87+
RangeTest:testFail_requireRange() (gas: 406)
88+
RangeTest:test_requireComplete() (gas: 322)
89+
RangeTest:test_requireRange() (gas: 3718)
90+
ReadBignum_Test:testFail_Int256_notbignum() (gas: 782)
91+
ReadBignum_Test:testFail_Integer_UInt256_max() (gas: 2268)
92+
ReadBignum_Test:testFail_NInt256_large() (gas: 1604)
93+
ReadBignum_Test:testFail_NInt256_maxu256() (gas: 1633)
94+
ReadBignum_Test:testFail_NInt256_overflow() (gas: 1699)
95+
ReadBignum_Test:testFail_UInt256_large() (gas: 1548)
96+
ReadBignum_Test:test_Integer() (gas: 14370)
97+
ReadBignum_Test:test_NInt256_max() (gas: 4905)
98+
ReadBignum_Test:test_NInt256_middle() (gas: 6383)
99+
ReadBignum_Test:test_NInt256_multi() (gas: 4308)
100+
ReadBignum_Test:test_NInt256_random(int256) (runs: 256, μ: 5816, ~: 5816)
101+
ReadBignum_Test:test_NInt256_single() (gas: 4309)
102+
ReadBignum_Test:test_UInt256_max() (gas: 4629)
103+
ReadBignum_Test:test_UInt256_middle() (gas: 6114)
104+
ReadBignum_Test:test_UInt256_multi() (gas: 4105)
105+
ReadBignum_Test:test_UInt256_random(uint256) (runs: 256, μ: 4689, ~: 4689)
106+
ReadBignum_Test:test_UInt256_single() (gas: 4488)
107+
ReadCidSha256_Test:testFail_Cid_NullableCid_zeroes() (gas: 912)
108+
ReadCidSha256_Test:testFail_Cid_nullCbor() (gas: 771)
109+
ReadCidSha256_Test:testFail_Cid_zeroCidCbor() (gas: 807)
110+
ReadCidSha256_Test:test_Cid() (gas: 1141)
111+
ReadCidSha256_Test:test_Cid_multicodec_raw() (gas: 1085)
112+
ReadCidSha256_Test:test_Cid_random(uint256) (runs: 256, μ: 4552, ~: 4552)
113+
ReadCidSha256_Test:test_NullableCid_nullCbor() (gas: 3446)
114+
ReadCidSha256_Test:test_NullableCid_random(uint256) (runs: 256, μ: 4412, ~: 4424)
115+
SimpleTest:testFail_decodeBool() (gas: 521)
116+
SimpleTest:testFail_skipNull() (gas: 444)
117+
SimpleTest:testFail_skipUndefined() (gas: 454)
118+
SimpleTest:test_decodeFalse() (gas: 3322)
119+
SimpleTest:test_decodeTrue() (gas: 3327)
120+
SimpleTest:test_skipNull() (gas: 435)
121+
SimpleTest:test_skipUndefined() (gas: 478)
122+
StringTest:testFail_String1() (gas: 463)
123+
StringTest:testFail_String32_long() (gas: 798)
124+
StringTest:testFail_String32_parameter() (gas: 353)
125+
StringTest:testFail_invalidString() (gas: 1066)
126+
StringTest:testFail_skipString() (gas: 519)
127+
StringTest:test_String1() (gas: 3383)
128+
StringTest:test_String32_short() (gas: 4266)
129+
StringTest:test_decodeEmptyString() (gas: 3804)
130+
StringTest:test_decodeLongString() (gas: 3929)
131+
StringTest:test_decodeMediumString() (gas: 1069)
132+
StringTest:test_decodeShortString() (gas: 3949)
133+
StringTest:test_skipString() (gas: 788)
134+
TagTest:testFail_notTag() (gas: 677)
135+
TagTest:testFail_unexpectedTag() (gas: 708)
136+
TagTest:test_decodeExpectedTag() (gas: 688)
137+
TagTest:test_decodeTag() (gas: 3599)
138+
UIntTest:testFail_invalidUInt8() (gas: 649)
139+
UIntTest:testFail_notUInt8() (gas: 580)
140+
UIntTest:testFail_outOfBoundsUInt16() (gas: 587)
141+
UIntTest:test_decodeLongUInt8() (gas: 3519)
142+
UIntTest:test_decodeShortUInt8() (gas: 3464)
143+
UIntTest:test_decodeSmallInts() (gas: 4178)
144+
UIntTest:test_decodeUInt16() (gas: 3642)
145+
UIntTest:test_decodeUInt32() (gas: 3670)
146+
UIntTest:test_decodeUInt64() (gas: 3717)
147+
UIntTest:test_decodeUInt8() (gas: 3520)

.github/workflows/test.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
8+
env:
9+
FOUNDRY_PROFILE: ci
10+
11+
jobs:
12+
check:
13+
strategy:
14+
fail-fast: true
15+
16+
name: Foundry project
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
submodules: recursive
22+
23+
- name: Install Foundry
24+
uses: foundry-rs/foundry-toolchain@v1
25+
with:
26+
version: nightly
27+
28+
- name: Show Forge version
29+
run: |
30+
forge --version
31+
32+
- name: Run Forge fmt
33+
run: |
34+
forge fmt --check
35+
id: fmt
36+
37+
- name: Run Forge build
38+
run: |
39+
forge build --sizes
40+
id: build
41+
42+
- name: Run Forge tests
43+
run: |
44+
forge test -vvv
45+
id: test

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Compiler files
2+
cache/
3+
out/
4+
5+
# Ignores development broadcast logs
6+
!/broadcast
7+
/broadcast/*/31337/
8+
/broadcast/**/dry-run/
9+
10+
# Docs
11+
docs/
12+
13+
# Dotenv file
14+
.env

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "lib/forge-std"]
2+
path = lib/forge-std
3+
url = https://github.com/@foundry-rs/forge-std

README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# @turbocrime/solidity-cbor
2+
3+
**This is a library for parsing CBOR.**
4+
5+
This library does not provide tools for writing CBOR.
6+
7+
This project was initially forked from [filecoin's CborDecode.sol](https://github.com/Zondax/filecoin-solidity/blob/master/contracts/v0.8/utils/CborDecode.sol) by Zondax AG.
8+
9+
[RFC 8949](https://www.iana.org/go/rfc8949)
10+
11+
[CBOR Simple Values Registry](https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml)
12+
13+
[CBOR Tags Registry](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml)
14+
15+
16+
## Usage
17+
18+
Most methods accept parameters `bytes` of CBOR data and `uint32` index, and return an updated index (and one or more values if appropriate). Since the data parameter is always first, you may sugar calls via `using` directive.
19+
20+
CBOR natively supports values up to `uint64`, so the typical values returned are `uint64`. Some methods return other types.
21+
22+
23+
Deserialization methods are a capitalized name of the type like `UInt`, `NInt`, `Text`, `Map`, and so on for every CBOR type. These return a value of the equivalent solidity type when possible.
24+
25+
When specific format constraints exist, some optimized method variants are available, such as `String1` when the next should be a 1-byte string.
26+
27+
You can peek at the type of the next item with `isBytes` and so on.
28+
29+
The caller is responsible for handling the index and using it to index the appropriate data. No 'cursor' metaphor is provided, but the example below demonstrates how a caller may define and use a cursor for convenience.
30+
31+
32+
```solidity
33+
using ReadCbor for bytes;
34+
35+
bytes constant someBytes = hex"84616103616102";
36+
37+
struct Cursor {
38+
bytes b;
39+
uint32 i;
40+
}
41+
42+
function example() pure {
43+
Cursor memory c = Cursor(someBytes, 0);
44+
uint32 len;
45+
46+
(c.i, len) = c.b.Array(c.i);
47+
48+
assert(len == 4);
49+
50+
string[] memory arrayStrs = new string[](len / 2);
51+
uint64[] memory arrayNums = new uint64[](len / 2);
52+
53+
// CBOR arrays may contain items of any type.
54+
for (uint32 arrayIdx = 0; arrayIdx < len; arrayIdx++) {
55+
if (c.b.isString(c.i)) {
56+
(c.i, arrayStrs[arrayIdx / 2]) = c.b.String(c.i);
57+
} else if (c.b.isUInt(c.i)) {
58+
(c.i, arrayNums[arrayIdx / 2]) = c.b.UInt(c.i);
59+
}
60+
}
61+
62+
c.b.requireComplete(c.i);
63+
}
64+
```
65+
66+
## Limitations
67+
68+
The CBOR format is very flexible and supports more types than solidity.
69+
70+
The caller is responsible for structure navigation and value interpretation.
71+
72+
### Tags
73+
74+
Tags must be parsed explicitly. The `Tag` method will simply return the tag value, or may be paramaterized to require a specific tag value.
75+
76+
### Primitives `null` and `undefined`
77+
78+
Solidity can't represent primitive values `null` and `undefined`.
79+
80+
The methods `Null` and `Undefined` will advance the index past a required value.
81+
82+
The methods `isNull` and `isUndefined` may be used to peek without advancing the index.
83+
84+
### Indefinite Length
85+
86+
Sequence and collection items of indefinite length are not supported.
87+
88+
### Collection Items
89+
90+
The `Array` and `Map` methods don't return fully-parsed collections, but simply return the collection size and advance the index to the first item.
91+
92+
Collection decoding can be quite complex, and CBOR collection types are more flexible than Solidity collection types. Since efficiency is critical in contract execution, and structures will vary widely, implementation is left up to the caller.
93+
94+
## Tag-specific parsers
95+
96+
All tagged items are valid CBOR and may be parsed manually, but [RFC 8949](https://www.rfc-editor.org/rfc/rfc8949) specifically mentions [stringref](https://cbor.schmorp.de/stringref) and [sharedref](https://cbor.schmorp.de/value-sharing) as tags which may require specialized support.
97+
98+
Some convenient specialized item parsers are provided in the `tags` directory.
99+
100+
### Tags 2 and 3: `ReadBignum`
101+
102+
Parses arbitrarily sized integers represented in CBOR as bytes, and returns the integer value.
103+
104+
Limited to `type(uint256).max` for tag 2 (positive) and `type(int256).min` for tag 3 (negative).
105+
106+
### Tag 42: `ReadCid`
107+
108+
Limited to the CID types appearing in atproto CBOR, specifically:
109+
110+
- DAG-CBOR SHA-256, 32 bytes
111+
- 'raw' SHA-256, 32 bytes

foundry.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[profile.default]
2+
src = "src"
3+
out = "out"
4+
libs = ["lib"]
5+
optimize = true
6+
optimizer_runs = 1000000
7+
8+
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
9+
10+
[fmt]
11+
int_types = "preserve"

0 commit comments

Comments
 (0)