From 8f52d25523229eed5fff3aab9f98c23856c76690 Mon Sep 17 00:00:00 2001 From: frrist Date: Wed, 20 May 2026 14:50:10 -0700 Subject: [PATCH 1/2] feat: support bigs ints --- .gitignore | 3 ++- ipld/datamodel/any.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ed9f9cc..5979734 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -coverage \ No newline at end of file +coverage +.idea diff --git a/ipld/datamodel/any.go b/ipld/datamodel/any.go index 9548f46..f65c5fe 100644 --- a/ipld/datamodel/any.go +++ b/ipld/datamodel/any.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "maps" + "math/big" "reflect" "slices" @@ -22,6 +23,8 @@ import ( // - Null (nil) // - Boolean (bool) // - Integer (int64, int) +// - BigInteger (*big.Int) — encoded as a CBOR bignum (tag 2), matching +// cbor-gen's *big.Int wire format. Non-negative only. // - String (string) // - Bytes ([]byte) // - List ([]Any) @@ -66,6 +69,10 @@ func (a *Any) MarshalCBOR(w io.Writer) error { return cbg.CborInt(v).MarshalCBOR(w) case int: return cbg.CborInt(v).MarshalCBOR(w) + case *big.Int: + return marshalCborBigInt(w, v) + case big.Int: + return marshalCborBigInt(w, &v) case bool: return cbg.CborBool(v).MarshalCBOR(w) case cid.Cid: @@ -153,6 +160,17 @@ func (a *Any) UnmarshalCBOR(r io.Reader) (err error) { } case cbg.MajTag: switch extra { + case 2: // CBOR bignum (tag 2 + byte string): cbor-gen's *big.Int wire format. + cr := cbg.NewCborReader(pr) + if _, _, err := cr.ReadHeader(); err != nil { // consume the bignum tag header + return err + } + b, err := cbg.ReadByteArray(cr, 256) + if err != nil { + return err + } + a.Value = new(big.Int).SetBytes(b) + return nil case 42: cbc := cbg.CborCid{} if err = cbc.UnmarshalCBOR(pr); err != nil { @@ -419,6 +437,29 @@ func (a *Any) UnmarshalDagJSON(r io.Reader) (err error) { return nil } +// marshalCborBigInt writes a non-negative *big.Int as a CBOR bignum +// (tag 2 + byte string), matching cbor-gen's *big.Int encoding so values +// round-trip through Any. cbor-gen does not support negative bignums. +func marshalCborBigInt(w io.Writer, v *big.Int) error { + if v == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if v.Sign() < 0 { + return fmt.Errorf("negative big.Int not supported") + } + cw := cbg.NewCborWriter(w) + if err := cw.WriteMajorTypeHeader(cbg.MajTag, 2); err != nil { + return err + } + b := v.Bytes() + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(b))); err != nil { + return err + } + _, err := cw.Write(b) + return err +} + func peekCborHeader(r io.Reader) (byte, uint64, io.Reader, error) { cr := cbg.NewCborReader(r) maj, extra, err := cr.ReadHeader() From 481eaab29d80a94c448e2750bfedf1acf27d641e Mon Sep 17 00:00:00 2001 From: frrist Date: Thu, 21 May 2026 11:42:11 -0700 Subject: [PATCH 2/2] address feedback --- .gitignore | 3 +- go.mod | 24 +++++++-------- go.sum | 46 +++++++++++++--------------- ipld/datamodel/any.go | 63 ++++++++++++++++++++++++++------------ ipld/datamodel/any_test.go | 34 ++++++++++++++++++++ 5 files changed, 113 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 5979734..ed9f9cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -coverage -.idea +coverage \ No newline at end of file diff --git a/go.mod b/go.mod index f0d03b5..c3f23c8 100644 --- a/go.mod +++ b/go.mod @@ -1,38 +1,38 @@ module github.com/fil-forge/ucantone -go 1.25 +go 1.25.0 // replace "github.com/alanshaw/dag-json-gen" => ../dag-json-gen require ( github.com/alanshaw/dag-json-gen v0.0.4 + github.com/filecoin-project/go-state-types v0.18.0 github.com/gobwas/glob v0.2.3 - github.com/ipfs/go-cid v0.5.0 + github.com/ipfs/go-cid v0.6.0 github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-multihash v0.2.3 - github.com/multiformats/go-varint v0.0.7 + github.com/multiformats/go-varint v0.1.0 github.com/stretchr/testify v1.11.1 github.com/whyrusleeping/cbor-gen v0.3.1 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b - golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/minio/sha256-simd v1.0.0 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect + github.com/multiformats/go-base36 v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect - golang.org/x/crypto v0.44.0 // indirect - golang.org/x/sys v0.40.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + golang.org/x/crypto v0.49.0 // indirect + golang.org/x/sys v0.42.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.1.6 // indirect + lukechampine.com/blake3 v1.4.1 // indirect pitr.ca/jsontokenizer v0.3.0 // indirect ) diff --git a/go.sum b/go.sum index 106b1c2..b53b78c 100644 --- a/go.sum +++ b/go.sum @@ -3,36 +3,34 @@ github.com/alanshaw/dag-json-gen v0.0.4/go.mod h1:rXxWw0SItP9QjxpRMpkju66h0KumF7 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/filecoin-project/go-state-types v0.18.0 h1:oDcjihXRlf2cM176atZzllp79Zc+kcbiuQM9DPL/1a4= +github.com/filecoin-project/go-state-types v0.18.0/go.mod h1:CcyG4ZQRDWW+QUY2WDf1KtVDRN7W4twjsfgnGbQfJVI= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= -github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/ipfs/go-cid v0.6.0 h1:DlOReBV1xhHBhhfy/gBNNTSyfOM6rLiIx9J7A4DGf30= +github.com/ipfs/go-cid v0.6.0/go.mod h1:NC4kS1LZjzfhK40UGmpXv5/qD2kcMzACYJNntCUiDhQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= -github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/multiformats/go-varint v0.1.0 h1:i2wqFp4sdl3IcIxfAonHQV9qU5OsZ4Ts9IOoETFs5dI= +github.com/multiformats/go-varint v0.1.0/go.mod h1:5KVAVXegtfmNQQm/lCY+ATvDzvJJhSkUlGQV9wgObdI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -49,18 +47,18 @@ gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRyS gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= -golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= -golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= -lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= pitr.ca/jsontokenizer v0.3.0 h1:Qr70hk4/wcpFEgu/6aJ+nvYQ6x/xS0WOkC627ceiI/M= pitr.ca/jsontokenizer v0.3.0/go.mod h1:3DJdA2QNOU6cI0XkH6pRKZ4Oe8G5SDRUQ6PFAwaQ3YY= diff --git a/ipld/datamodel/any.go b/ipld/datamodel/any.go index f65c5fe..38dd054 100644 --- a/ipld/datamodel/any.go +++ b/ipld/datamodel/any.go @@ -7,12 +7,12 @@ import ( "fmt" "io" "maps" - "math/big" "reflect" "slices" jsg "github.com/alanshaw/dag-json-gen" "github.com/fil-forge/ucantone/ipld" + "github.com/filecoin-project/go-state-types/big" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" ) @@ -23,8 +23,9 @@ import ( // - Null (nil) // - Boolean (bool) // - Integer (int64, int) -// - BigInteger (*big.Int) — encoded as a CBOR bignum (tag 2), matching -// cbor-gen's *big.Int wire format. Non-negative only. +// - BigInteger (go-state-types/big.Int) — encoded as a CBOR bignum: tag 2 +// for non-negative values and tag 3 for negative values (RFC 8949). +// CBOR only; big integers are not supported in DAG-JSON. // - String (string) // - Bytes ([]byte) // - List ([]Any) @@ -43,6 +44,7 @@ type Any struct { // - bool // - int // - int64 +// - big.Int (go-state-types/big; CBOR only) // - string // - []byte // - slice @@ -69,10 +71,14 @@ func (a *Any) MarshalCBOR(w io.Writer) error { return cbg.CborInt(v).MarshalCBOR(w) case int: return cbg.CborInt(v).MarshalCBOR(w) - case *big.Int: - return marshalCborBigInt(w, v) case big.Int: - return marshalCborBigInt(w, &v) + return marshalCborBigInt(w, v) + case *big.Int: + if v == nil { + _, err := w.Write(cbg.CborNull) + return err + } + return marshalCborBigInt(w, *v) case bool: return cbg.CborBool(v).MarshalCBOR(w) case cid.Cid: @@ -160,16 +166,19 @@ func (a *Any) UnmarshalCBOR(r io.Reader) (err error) { } case cbg.MajTag: switch extra { - case 2: // CBOR bignum (tag 2 + byte string): cbor-gen's *big.Int wire format. - cr := cbg.NewCborReader(pr) - if _, _, err := cr.ReadHeader(); err != nil { // consume the bignum tag header + case 2: // CBOR positive bignum (tag 2 + byte string): value = n + b, err := readBignumBytes(pr) + if err != nil { return err } - b, err := cbg.ReadByteArray(cr, 256) + a.Value = big.PositiveFromUnsignedBytes(b) + return nil + case 3: // CBOR negative bignum (tag 3 + byte string): value = -1 - n + b, err := readBignumBytes(pr) if err != nil { return err } - a.Value = new(big.Int).SetBytes(b) + a.Value = big.Sub(big.NewInt(-1), big.PositiveFromUnsignedBytes(b)) return nil case 42: cbc := cbg.CborCid{} @@ -264,6 +273,8 @@ func (a *Any) MarshalDagJSON(w io.Writer) error { return jw.WriteInt64(v) case int: return jw.WriteInt64(int64(v)) + case big.Int, *big.Int: + return fmt.Errorf("big integers are not supported in DAG-JSON") case bool: return jw.WriteBool(v) case cid.Cid: @@ -437,22 +448,26 @@ func (a *Any) UnmarshalDagJSON(r io.Reader) (err error) { return nil } -// marshalCborBigInt writes a non-negative *big.Int as a CBOR bignum -// (tag 2 + byte string), matching cbor-gen's *big.Int encoding so values -// round-trip through Any. cbor-gen does not support negative bignums. -func marshalCborBigInt(w io.Writer, v *big.Int) error { - if v == nil { +// marshalCborBigInt writes a big.Int as a CBOR bignum (RFC 8949): tag 2 for +// non-negative values and tag 3 for negative values, each followed by a byte +// string holding the big-endian magnitude. A negative value v is encoded as +// the magnitude of n = -1 - v, so it round-trips via value = -1 - n on decode. +func marshalCborBigInt(w io.Writer, v big.Int) error { + if v.Nil() { _, err := w.Write(cbg.CborNull) return err } + tag := uint64(2) + mag := v // non-negative: encode the magnitude directly if v.Sign() < 0 { - return fmt.Errorf("negative big.Int not supported") + tag = 3 + mag = big.Sub(big.NewInt(-1), v) // n = -1 - v } cw := cbg.NewCborWriter(w) - if err := cw.WriteMajorTypeHeader(cbg.MajTag, 2); err != nil { + if err := cw.WriteMajorTypeHeader(cbg.MajTag, tag); err != nil { return err } - b := v.Bytes() + b := mag.Int.Bytes() // raw big-endian magnitude (no sign prefix) if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(b))); err != nil { return err } @@ -460,6 +475,16 @@ func marshalCborBigInt(w io.Writer, v *big.Int) error { return err } +// readBignumBytes consumes a CBOR bignum tag header and returns the bytes of +// the following byte string (the big-endian magnitude). +func readBignumBytes(r io.Reader) ([]byte, error) { + cr := cbg.NewCborReader(r) + if _, _, err := cr.ReadHeader(); err != nil { // consume the bignum tag header + return nil, err + } + return cbg.ReadByteArray(cr, 256) +} + func peekCborHeader(r io.Reader) (byte, uint64, io.Reader, error) { cr := cbg.NewCborReader(r) maj, extra, err := cr.ReadHeader() diff --git a/ipld/datamodel/any_test.go b/ipld/datamodel/any_test.go index 4d9809a..5f560ee 100644 --- a/ipld/datamodel/any_test.go +++ b/ipld/datamodel/any_test.go @@ -8,6 +8,7 @@ import ( "github.com/fil-forge/ucantone/ipld" "github.com/fil-forge/ucantone/ipld/datamodel" "github.com/fil-forge/ucantone/testutil" + "github.com/filecoin-project/go-state-types/big" "github.com/stretchr/testify/require" ) @@ -61,3 +62,36 @@ func TestAny(t *testing.T) { }) } } + +// big.Int is CBOR only (not supported in DAG-JSON), so it round-trips through +// its own test rather than the shared list above. +func TestAnyBigInt(t *testing.T) { + values := []big.Int{ + big.NewInt(0), + big.NewInt(138), + big.NewInt(-138), + big.MustFromString("340282366920938463463374607431768211457"), // > maxUint64, positive + big.MustFromString("-340282366920938463463374607431768211457"), // < minInt64, negative + } + + for _, v := range values { + t.Run(fmt.Sprintf("dag-cbor %s", v), func(t *testing.T) { + initial := datamodel.NewAny(v) + + var buf bytes.Buffer + err := initial.MarshalCBOR(&buf) + require.NoError(t, err) + + var decoded datamodel.Any + err = decoded.UnmarshalCBOR(&buf) + require.NoError(t, err) + require.Equal(t, v, decoded.Value) + }) + + t.Run(fmt.Sprintf("dag-json unsupported %s", v), func(t *testing.T) { + var buf bytes.Buffer + err := datamodel.NewAny(v).MarshalDagJSON(&buf) + require.Error(t, err) + }) + } +}