From 32954534aeaeea2f2f1cf57bc6de7fdf837361e0 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 31 Mar 2023 16:00:58 +0200 Subject: [PATCH 01/39] chore!: bump to celestia-app v0.14.0-rc0 --- api/gateway/share.go | 7 +- go.mod | 42 +++++---- go.sum | 89 +++++++++++-------- libs/utils/shares.go | 16 ++++ share/availability/light/availability_test.go | 15 +++- share/eds/eds.go | 4 +- share/eds/eds_test.go | 6 +- share/empty.go | 19 +++- 8 files changed, 127 insertions(+), 71 deletions(-) create mode 100644 libs/utils/shares.go diff --git a/api/gateway/share.go b/api/gateway/share.go index caa1714eef..4632d7e966 100644 --- a/api/gateway/share.go +++ b/api/gateway/share.go @@ -13,6 +13,7 @@ import ( "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/celestia-node/header" + "github.com/celestiaorg/celestia-node/libs/utils" "github.com/celestiaorg/celestia-node/share" ) @@ -113,7 +114,11 @@ func (h *Handler) getShares(ctx context.Context, height uint64, nID namespace.ID } func dataFromShares(input []share.Share) (data [][]byte, err error) { - sequences, err := shares.ParseShares(input) + appShares, err := utils.AppSharesFromBytes(input) + if err != nil { + return nil, err + } + sequences, err := shares.ParseShares(appShares) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 52b3c4a833..78301e4ec5 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/benbjohnson/clock v1.3.0 - github.com/celestiaorg/celestia-app v0.12.2 + github.com/celestiaorg/celestia-app v0.14.0-rc0 github.com/celestiaorg/go-header v0.2.3 github.com/celestiaorg/go-libp2p-messenger v0.2.0 github.com/celestiaorg/nmt v0.15.0 @@ -55,7 +55,7 @@ require ( github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/tendermint/tendermint v0.35.4 go.opentelemetry.io/otel v1.13.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.34.0 @@ -68,7 +68,7 @@ require ( go.uber.org/fx v1.18.2 go.uber.org/multierr v1.9.0 golang.org/x/crypto v0.7.0 - golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 + golang.org/x/exp v0.0.0-20230206171751-46f607a40771 golang.org/x/sync v0.1.0 golang.org/x/text v0.8.0 google.golang.org/grpc v1.53.0 @@ -95,7 +95,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/btcsuite/btcd v0.22.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4 // indirect github.com/celestiaorg/quantum-gravity-bridge v1.3.0 // indirect @@ -105,6 +104,7 @@ require ( github.com/chzyer/readline v1.5.0 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect + github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/containerd/cgroups v1.0.4 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -113,16 +113,17 @@ require ( github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogoproto v1.4.2 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect - github.com/cosmos/iavl v0.19.4 // indirect + github.com/cosmos/iavl v0.19.5 // indirect github.com/cosmos/ibc-go/v6 v6.1.0 // indirect - github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect + github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect github.com/cskr/pubsub v1.0.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/deckarep/golang-set v1.8.0 // indirect + github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect @@ -131,7 +132,7 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/etclabscore/go-jsonschema-walk v0.0.6 // indirect - github.com/ethereum/go-ethereum v1.10.26 // indirect + github.com/ethereum/go-ethereum v1.11.5 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -147,7 +148,7 @@ require ( github.com/go-openapi/jsonreference v0.19.4 // indirect github.com/go-openapi/spec v0.19.11 // indirect github.com/go-openapi/swag v0.19.11 // indirect - github.com/go-stack/stack v1.8.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect @@ -156,7 +157,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.0.1 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/orderedcode v0.0.1 // indirect @@ -182,10 +183,13 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect + github.com/holiman/uint256 v1.2.0 // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/iancoleman/orderedmap v0.1.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/influxdata/influxdb-client-go/v2 v2.12.2 // indirect + github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitswap v0.12.0 // indirect github.com/ipfs/go-block-format v0.1.1 // indirect @@ -208,7 +212,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.15.12 // indirect + github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.2.3 // indirect github.com/klauspost/reedsolomon v1.11.1 // indirect github.com/koron/go-ssdp v0.0.3 // indirect @@ -258,8 +262,8 @@ require ( github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.2.1 // indirect github.com/quic-go/qtls-go1-20 v0.1.1 // indirect @@ -270,7 +274,6 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/regen-network/cosmos-proto v0.3.1 // indirect github.com/rivo/uniseg v0.4.2 // indirect - github.com/rjeczalik/notify v0.9.1 // indirect github.com/rs/cors v1.8.2 // indirect github.com/rs/zerolog v1.27.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect @@ -282,10 +285,10 @@ require ( github.com/spf13/viper v1.14.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/tendermint/btcd v0.1.1 // indirect - github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tendermint/tm-db v0.6.7 // indirect + github.com/tidwall/btree v1.5.0 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/ulikunitz/xz v0.5.8 // indirect @@ -294,7 +297,7 @@ require ( github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/zondax/hid v0.9.1 // indirect - github.com/zondax/ledger-go v0.14.0 // indirect + github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect @@ -323,8 +326,9 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.8.0-sdk-v0.46.7 + github.com/celestiaorg/celestia-app => ../celestia-app + github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11 github.com/filecoin-project/dagstore => github.com/celestiaorg/dagstore v0.0.0-20221014072825-395797efb659 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.15.0-tm-v0.34.23 + github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27 ) diff --git a/go.sum b/go.sum index cd4563a293..d624146082 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,7 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic= @@ -180,6 +181,7 @@ github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/i github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= @@ -187,7 +189,6 @@ github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufo github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= @@ -200,12 +201,10 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/celestiaorg/celestia-app v0.12.2 h1:Mlxzz2SS+uvE4RnbSuXAh4MagiJBW7GnhDa+8kVbzKE= -github.com/celestiaorg/celestia-app v0.12.2/go.mod h1:lKhL1Oxk4Z29M+GQ25luTHBgwSvgiT4puPeBrjdsgXc= -github.com/celestiaorg/celestia-core v1.15.0-tm-v0.34.23 h1:BHvn41IHOtvHeX1VZqO/xBFIHj93llcw9ZQfNxyVRlI= -github.com/celestiaorg/celestia-core v1.15.0-tm-v0.34.23/go.mod h1:nL+vkAMKy/A8wWemWqMwBy4pOGWYYbboAVTEe3N5gIU= -github.com/celestiaorg/cosmos-sdk v1.8.0-sdk-v0.46.7 h1:EADZy33ufskVIy6Rj6jbi3SOVCeYYo26zUi7iYx+QR0= -github.com/celestiaorg/cosmos-sdk v1.8.0-sdk-v0.46.7/go.mod h1:vg3Eza9adJJ5Mdx6boz5MpZsZcTZyrfTVYZHyi2zLm4= +github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27 h1:7EIZ0pzRB4eaRnsscTLtLruJhokmcinHUgB8ruDh6sU= +github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27/go.mod h1:gMRZPCntAn3FvoF9/NBszOolf89Ggrj7qLbeFIUFam4= +github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11 h1:4pHUj2JP27fEJ1daxlJNGi/jkCiAiRx78sAftzpCbGg= +github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11/go.mod h1:O3Pnh/fALx6KV5678ckfemIzvidYbVF5H8ol1rb/3+E= github.com/celestiaorg/dagstore v0.0.0-20221014072825-395797efb659 h1:f3205vw3GYBtMiNoS+qB6IuHSs50Iwqsm9lNIikLTCk= github.com/celestiaorg/dagstore v0.0.0-20221014072825-395797efb659/go.mod h1:ta/DlqIH10bvhwqJIw51Nq3QU4XVMp6pz3f0Deve9fM= github.com/celestiaorg/go-header v0.2.3 h1:41r60OtAeexWC3J3eTELgWfzcdKR2taFlfcJ/2IHZD4= @@ -265,11 +264,17 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= +github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= +github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= @@ -308,12 +313,12 @@ github.com/cosmos/gogoproto v1.4.2 h1:UeGRcmFW41l0G0MiefWhkPEVEwvu78SZsHBvI78dAY github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= -github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok= -github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= +github.com/cosmos/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= +github.com/cosmos/iavl v0.19.5/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/ibc-go/v6 v6.1.0 h1:o7oXws2vKkKfOFzJI+oNylRn44PCNt5wzHd/zKQKbvQ= github.com/cosmos/ibc-go/v6 v6.1.0/go.mod h1:CY3zh2HLfetRiW8LY6kVHMATe90Wj/UOoY8T6cuB0is= -github.com/cosmos/ledger-cosmos-go v0.12.1 h1:sMBxza5p/rNK/06nBSNmsI/WDqI0pVJFVNihy1Y984w= -github.com/cosmos/ledger-cosmos-go v0.12.1/go.mod h1:dhO6kj+Y+AHIOgAe4L9HL/6NDdyyth4q238I9yFpD2g= +github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= +github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -339,8 +344,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= @@ -348,6 +354,7 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= +github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= @@ -410,8 +417,8 @@ github.com/etclabscore/go-jsonschema-walk v0.0.6/go.mod h1:VdfDY72AFAiUhy0ZXEaWS github.com/etclabscore/go-openrpc-reflect v0.0.37 h1:IH0e7JqIvR9OhbbFWi/BHIkXrqbR3Zyia3RJ733eT6c= github.com/etclabscore/go-openrpc-reflect v0.0.37/go.mod h1:0404Ky3igAasAOpyj1eESjstTyneBAIk5PgJFbK4s5E= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s= -github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= +github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= +github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= @@ -449,6 +456,7 @@ github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqG github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -513,8 +521,9 @@ github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7a github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -530,6 +539,7 @@ github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= @@ -584,8 +594,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -761,10 +771,13 @@ github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb-client-go/v2 v2.12.2 h1:uYABKdrEKlYm+++qfKdbgaHKBPmoWR5wpbmj6MBB/2g= +github.com/influxdata/influxdb-client-go/v2 v2.12.2/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= @@ -961,8 +974,8 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= -github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -992,6 +1005,7 @@ github.com/kr/pty v1.1.3/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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= @@ -1576,8 +1590,8 @@ github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1588,9 +1602,8 @@ github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= @@ -1618,7 +1631,6 @@ github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -1717,8 +1729,8 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -1737,22 +1749,23 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= -github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= -github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= -github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= +github.com/tidwall/btree v1.5.0 h1:iV0yVY/frd7r6qGBXfEYs7DH0gTDgrKTrDjS7xt/IyQ= +github.com/tidwall/btree v1.5.0/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= @@ -1776,8 +1789,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -1791,7 +1804,7 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= +github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -1835,8 +1848,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= -github.com/zondax/ledger-go v0.14.0 h1:dlMC7aO8Wss1CxBq2I96kZ69Nh1ligzbs8UWOtq/AsA= -github.com/zondax/ledger-go v0.14.0/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= +github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN4c= +github.com/zondax/ledger-go v0.14.1/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= gitlab.com/NebulousLabs/errors v0.0.0-20171229012116-7ead97ef90b8/go.mod h1:ZkMZ0dpQyWwlENaeZVBiQRjhMEZvk6VTXquzl3FOFP8= gitlab.com/NebulousLabs/errors v0.0.0-20200929122200-06c536cf6975 h1:L/ENs/Ar1bFzUeKx6m3XjlmBgIUlykX9dzvp5k9NGxc= gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs= @@ -1981,8 +1994,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= golang.org/x/exp v0.0.0-20210714144626-1041f73d31d8/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= -golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 h1:5sPMf9HJXrvBWIamTw+rTST0bZ3Mho2n1p58M0+W99c= -golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -2247,7 +2260,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/libs/utils/shares.go b/libs/utils/shares.go new file mode 100644 index 0000000000..f5d7868bf4 --- /dev/null +++ b/libs/utils/shares.go @@ -0,0 +1,16 @@ +package utils + +import ( + "github.com/celestiaorg/celestia-app/pkg/shares" +) + +func AppSharesFromBytes(bytes [][]byte) (result []shares.Share, err error) { + for _, share := range bytes { + appShare, err := shares.NewShare(share) + if err != nil { + return nil, err + } + result = append(result, *appShare) + } + return result, nil +} diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index def9095d86..e8c4ebd462 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -21,6 +21,7 @@ import ( appshares "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-node/header" + "github.com/celestiaorg/celestia-node/libs/utils" "github.com/celestiaorg/celestia-node/share" availability_test "github.com/celestiaorg/celestia-node/share/availability/test" ) @@ -293,11 +294,15 @@ func TestSharesRoundTrip(t *testing.T) { { myShares := make([][]byte, 0) for _, sh := range shares { - if bytes.Equal(namespace, sh[:8]) { - myShares = append(myShares, sh) + ns, err := sh.Namespace() + require.NoError(t, err) + if bytes.Equal(namespace, ns.Bytes()) { + myShares = append(myShares, sh.ToBytes()) } } - blobs, err := appshares.ParseBlobs(myShares) + appShares, err := utils.AppSharesFromBytes(myShares) + assert.NoError(t, err) + blobs, err := appshares.ParseBlobs(appShares) require.NoError(t, err) assert.Len(t, blobs, len(msgsInNamespace)) for i := range blobs { @@ -316,7 +321,9 @@ func TestSharesRoundTrip(t *testing.T) { require.NoError(t, shares.Verify(&dah, namespace)) require.NotEmpty(t, shares) - blobs, err := appshares.ParseBlobs(shares.Flatten()) + appShares, err := utils.AppSharesFromBytes(shares.Flatten()) + assert.NoError(t, err) + blobs, err := appshares.ParseBlobs(appShares) require.NoError(t, err) assert.Len(t, blobs, len(msgsInNamespace)) for i := range blobs { diff --git a/share/eds/eds.go b/share/eds/eds.go index b183731a18..0f69745879 100644 --- a/share/eds/eds.go +++ b/share/eds/eds.go @@ -18,8 +18,8 @@ import ( "github.com/ipld/go-car/util" "github.com/minio/sha256-simd" - "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/da" + "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/celestia-app/pkg/wrapper" "github.com/celestiaorg/nmt" "github.com/celestiaorg/rsmt2d" @@ -223,7 +223,7 @@ func prependNamespace(quadrant int, share []byte) []byte { case 0: return append(share[:ipld.NamespaceSize], share...) case 1, 2, 3: - return append(appconsts.ParitySharesNamespaceID, share...) + return append(namespace.ParitySharesNamespace.Bytes(), share...) default: panic("invalid quadrant") } diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index 5eac847ac2..4e2b4b6267 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -15,8 +15,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/da" + "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/rsmt2d" "github.com/celestiaorg/celestia-node/share" @@ -32,8 +32,8 @@ var f embed.FS func TestQuadrantOrder(t *testing.T) { // TODO: add more test cases nID := []byte{0, 0, 0, 0, 0, 0, 0, 0} - parity := append(appconsts.ParitySharesNamespaceID, nID...) //nolint - doubleNID := append(nID, nID...) //nolint + parity := append(namespace.ParitySharesNamespace.Bytes(), nID...) //nolint + doubleNID := append(nID, nID...) //nolint result, _ := rsmt2d.ComputeExtendedDataSquare([][]byte{ append(nID, 1), append(nID, 2), append(nID, 3), append(nID, 4), diff --git a/share/empty.go b/share/empty.go index 6b5d7bb1e8..ea4544f760 100644 --- a/share/empty.go +++ b/share/empty.go @@ -21,7 +21,10 @@ var ( func init() { // compute empty block EDS and DAH for it - shares := emptyDataSquare() + shares, err := emptyDataSquare() + if err != nil { + panic(fmt.Errorf("failed to create empty data square: %w", err)) + } squareSize := uint64(math.Sqrt(float64(appconsts.DefaultMinSquareSize))) eds, err := da.ExtendShares(squareSize, shares) if err != nil { @@ -51,7 +54,11 @@ func EmptyRoot() *Root { // redundant storing of empty block data so that it is only stored once and returned // upon request for a block with an empty data square. Ref: header/constructors.go#L56 func EnsureEmptySquareExists(ctx context.Context, bServ blockservice.BlockService) (*rsmt2d.ExtendedDataSquare, error) { - return AddShares(ctx, emptyDataSquare(), bServ) + shares, err := emptyDataSquare() + if err != nil { + return nil, err + } + return AddShares(ctx, shares, bServ) } // EmptyExtendedDataSquare returns the EDS of the empty block data square. @@ -60,6 +67,10 @@ func EmptyExtendedDataSquare() *rsmt2d.ExtendedDataSquare { } // emptyDataSquare returns the minimum size data square filled with tail padding. -func emptyDataSquare() [][]byte { - return shares.ToBytes(shares.TailPaddingShares(appconsts.MinShareCount)) +func emptyDataSquare() ([][]byte, error) { + result, err := shares.TailPaddingShares(appconsts.MinShareCount) + if err != nil { + return nil, err + } + return shares.ToBytes(result), nil } From a135598796a17ac8be8b83e60bc376608d05abe9 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 31 Mar 2023 21:34:15 +0200 Subject: [PATCH 02/39] fix tests --- api/gateway/share.go | 3 +-- api/gateway/share_test.go | 24 +++++++++---------- libs/utils/shares.go | 16 ------------- share/availability/light/availability_test.go | 5 ++-- share/test_helpers.go | 15 +++++------- 5 files changed, 21 insertions(+), 42 deletions(-) delete mode 100644 libs/utils/shares.go diff --git a/api/gateway/share.go b/api/gateway/share.go index 4632d7e966..2bde5ced4d 100644 --- a/api/gateway/share.go +++ b/api/gateway/share.go @@ -13,7 +13,6 @@ import ( "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/libs/utils" "github.com/celestiaorg/celestia-node/share" ) @@ -114,7 +113,7 @@ func (h *Handler) getShares(ctx context.Context, height uint64, nID namespace.ID } func dataFromShares(input []share.Share) (data [][]byte, err error) { - appShares, err := utils.AppSharesFromBytes(input) + appShares, err := shares.FromBytes(input) if err != nil { return nil, err } diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index aeccc9eb02..bebf0ee7d7 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -18,10 +18,10 @@ func Test_dataFromShares(t *testing.T) { } smallTxInput := padShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace id + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace 0x1, // info byte 0x0, 0x0, 0x0, 0x2, // 1 byte (unit) + 1 byte (unit length) = 2 bytes sequence length - 0x0, 0x0, 0x0, 17, // reserved bytes + 0x0, 0x0, 0x0, 0x2a, // reserved bytes 0x1, // unit length of first transaction 0xa, // data of first transaction }) @@ -29,17 +29,17 @@ func Test_dataFromShares(t *testing.T) { largeTxInput := [][]byte{ fillShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace id + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace 0x1, // info byte 0x0, 0x0, 0x2, 0x2, // 512 (unit) + 2 (unit length) = 514 sequence length - 0x0, 0x0, 0x0, 17, // reserved bytes + 0x0, 0x0, 0x0, 0x2a, // reserved bytes 128, 4, // unit length of transaction is 512 }, 0xc), // data of transaction padShare(append([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace id + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace 0x0, // info byte 0x0, 0x0, 0x0, 0x0, // reserved bytes - }, bytes.Repeat([]byte{0xc}, 19)..., // continuation data of transaction + }, bytes.Repeat([]byte{0xc}, 44)..., // continuation data of transaction )), } largeTxData := []byte{128, 4} @@ -47,17 +47,17 @@ func Test_dataFromShares(t *testing.T) { largePfbTxInput := [][]byte{ fillShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace id + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace 0x1, // info byte 0x0, 0x0, 0x2, 0x2, // 512 (unit) + 2 (unit length) = 514 sequence length - 0x0, 0x0, 0x0, 17, // reserved bytes + 0x0, 0x0, 0x0, 0x2a, // reserved bytes 128, 4, // unit length of transaction is 512 }, 0xc), // data of transaction padShare(append([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace id + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace 0x0, // info byte 0x0, 0x0, 0x0, 0x0, // reserved bytes - }, bytes.Repeat([]byte{0xc}, 19)..., // continuation data of transaction + }, bytes.Repeat([]byte{0xc}, 44)..., // continuation data of transaction )), } largePfbTxData := []byte{128, 4} @@ -73,8 +73,8 @@ func Test_dataFromShares(t *testing.T) { { name: "returns an error when shares contain two different namespaces", input: [][]byte{ - {0, 0, 0, 0, 0, 0, 0, 1}, - {0, 0, 0, 0, 0, 0, 0, 2}, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, }, want: nil, wantErr: true, diff --git a/libs/utils/shares.go b/libs/utils/shares.go deleted file mode 100644 index f5d7868bf4..0000000000 --- a/libs/utils/shares.go +++ /dev/null @@ -1,16 +0,0 @@ -package utils - -import ( - "github.com/celestiaorg/celestia-app/pkg/shares" -) - -func AppSharesFromBytes(bytes [][]byte) (result []shares.Share, err error) { - for _, share := range bytes { - appShare, err := shares.NewShare(share) - if err != nil { - return nil, err - } - result = append(result, *appShare) - } - return result, nil -} diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index e8c4ebd462..8c1e098c42 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -21,7 +21,6 @@ import ( appshares "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-node/header" - "github.com/celestiaorg/celestia-node/libs/utils" "github.com/celestiaorg/celestia-node/share" availability_test "github.com/celestiaorg/celestia-node/share/availability/test" ) @@ -300,7 +299,7 @@ func TestSharesRoundTrip(t *testing.T) { myShares = append(myShares, sh.ToBytes()) } } - appShares, err := utils.AppSharesFromBytes(myShares) + appShares, err := appshares.FromBytes(myShares) assert.NoError(t, err) blobs, err := appshares.ParseBlobs(appShares) require.NoError(t, err) @@ -321,7 +320,7 @@ func TestSharesRoundTrip(t *testing.T) { require.NoError(t, shares.Verify(&dah, namespace)) require.NotEmpty(t, shares) - appShares, err := utils.AppSharesFromBytes(shares.Flatten()) + appShares, err := appshares.FromBytes(shares.Flatten()) assert.NoError(t, err) blobs, err := appshares.ParseBlobs(appShares) require.NoError(t, err) diff --git a/share/test_helpers.go b/share/test_helpers.go index 6700ebd9ef..387db93a01 100644 --- a/share/test_helpers.go +++ b/share/test_helpers.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/celestia-app/pkg/wrapper" "github.com/celestiaorg/rsmt2d" ) @@ -46,23 +47,19 @@ func RandEDS(t require.TestingT, size int) *rsmt2d.ExtendedDataSquare { // to be able to take both a *testing.T and a *testing.B. func RandShares(t require.TestingT, total int) []Share { if total&(total-1) != 0 { - t.Errorf("Namespace total must be power of 2: %d", total) + t.Errorf("total must be power of 2: %d", total) t.FailNow() } shares := make([]Share, total) for i := range shares { - nid := make([]byte, Size) - _, err := mrand.Read(nid[:NamespaceSize]) //nolint:gosec + share := make([]byte, Size) + copy(share[:NamespaceSize], namespace.RandomNamespace().Bytes()) + _, err := mrand.Read(share[NamespaceSize:]) //nolint:gosec require.NoError(t, err) - shares[i] = nid + shares[i] = share } sort.Slice(shares, func(i, j int) bool { return bytes.Compare(shares[i], shares[j]) < 0 }) - for i := range shares { - _, err := mrand.Read(shares[i][NamespaceSize:]) //nolint:gosec - require.NoError(t, err) - } - return shares } From 769f48e721a766cd3f80cc4d73f78198c6e7c205 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 31 Mar 2023 22:06:24 +0200 Subject: [PATCH 03/39] wip: mark tests that need fixing --- share/availability/light/availability_test.go | 9 ++++++--- share/eds/eds_test.go | 3 ++- share/getters/getter_test.go | 14 +++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 8c1e098c42..473d7ce25b 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -18,6 +18,7 @@ import ( core "github.com/tendermint/tendermint/types" "github.com/celestiaorg/celestia-app/pkg/da" + "github.com/celestiaorg/celestia-app/pkg/namespace" appshares "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-node/header" @@ -80,6 +81,7 @@ func TestGetShare(t *testing.T) { } } +// TODO: fix test func TestService_GetSharesByNamespace(t *testing.T) { var tests = []struct { squareSize int @@ -99,10 +101,10 @@ func TestService_GetSharesByNamespace(t *testing.T) { idx2 := n / 2 if tt.expectedShareCount > 1 { // make it so that two rows have the same namespace ID - copy(randShares[idx2][:8], randShares[idx1][:8]) + copy(randShares[idx2][:namespace.NamespaceSize], randShares[idx1][:namespace.NamespaceSize]) } root := availability_test.FillBS(t, bServ, randShares) - randNID := randShares[idx1][:8] + randNID := randShares[idx1][:namespace.NamespaceSize] shares, err := getter.GetSharesByNamespace(context.Background(), root, randNID) require.NoError(t, err) @@ -139,7 +141,7 @@ func TestService_GetSharesByNamespaceNotFound(t *testing.T) { getter, root := GetterWithRandSquare(t, 1) root.RowsRoots = nil - shares, err := getter.GetSharesByNamespace(context.Background(), root, []byte{1, 1, 1, 1, 1, 1, 1, 1}) + shares, err := getter.GetSharesByNamespace(context.Background(), root, namespace.RandomNamespace().Bytes()) assert.Len(t, shares, 0) assert.NoError(t, err) } @@ -168,6 +170,7 @@ func BenchmarkService_GetSharesByNamespace(b *testing.B) { } } +// TODO: fix test func TestSharesRoundTrip(t *testing.T) { getter, store := EmptyGetter() ctx, cancel := context.WithCancel(context.Background()) diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index 4e2b4b6267..b33242109e 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -29,9 +29,10 @@ var exampleRoot string //go:embed "testdata/example.car" var f embed.FS +// TODO: fix test func TestQuadrantOrder(t *testing.T) { // TODO: add more test cases - nID := []byte{0, 0, 0, 0, 0, 0, 0, 0} + nID := bytes.Repeat([]byte{0}, namespace.NamespaceSize) parity := append(namespace.ParitySharesNamespace.Bytes(), nID...) //nolint doubleNID := append(nID, nID...) //nolint result, _ := rsmt2d.ComputeExtendedDataSquare([][]byte{ diff --git a/share/getters/getter_test.go b/share/getters/getter_test.go index 9695eeadb5..1c644dc53b 100644 --- a/share/getters/getter_test.go +++ b/share/getters/getter_test.go @@ -112,6 +112,7 @@ func TestStoreGetter(t *testing.T) { assert.True(t, share.EqualEDS(eds, retrievedEDS)) }) + // TODO: fix test t.Run("GetSharesByNamespace", func(t *testing.T) { eds, nID, dah := randomEDSWithDoubledNamespace(t, 4) err = edsStore.Put(ctx, dah.Hash(), eds) @@ -139,8 +140,15 @@ func randomEDSWithDoubledNamespace(t *testing.T, size int) (*rsmt2d.ExtendedData randShares := share.RandShares(t, n) idx1 := (n - 1) / 2 idx2 := n / 2 - // make it so that two rows have the same namespace ID - copy(randShares[idx2][:8], randShares[idx1][:8]) + + // Make it so that the two shares have a common namespace. For example if + // size=4, the original data square looks like this: + // _ D D _ + // _ _ _ _ + // _ _ _ _ + // _ _ _ _ + // where the D shares have a common namespace. + copy(randShares[idx2][:share.NamespaceSize], randShares[idx1][:share.NamespaceSize]) eds, err := rsmt2d.ComputeExtendedDataSquare( randShares, @@ -150,5 +158,5 @@ func randomEDSWithDoubledNamespace(t *testing.T, size int) (*rsmt2d.ExtendedData require.NoError(t, err, "failure to recompute the extended data square") dah := da.NewDataAvailabilityHeader(eds) - return eds, randShares[idx1][:8], dah + return eds, randShares[idx1][:share.NamespaceSize], dah } From 647c90e74e72e251a497f12642c954d631c68d6a Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 7 Apr 2023 16:21:45 -0400 Subject: [PATCH 04/39] wip: debug TestService_GetSharesByNamespace --- share/availability/light/availability_test.go | 12 ++++++------ share/getters/utils.go | 13 ++++++++++++- share/ipld/nmt.go | 1 + share/test_helpers.go | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 473d7ce25b..1739e851fb 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -88,17 +88,17 @@ func TestService_GetSharesByNamespace(t *testing.T) { expectedShareCount int }{ {squareSize: 4, expectedShareCount: 2}, - {squareSize: 16, expectedShareCount: 2}, - {squareSize: 128, expectedShareCount: 2}, + // {squareSize: 16, expectedShareCount: 2}, + // {squareSize: 128, expectedShareCount: 2}, } for _, tt := range tests { t.Run("size: "+strconv.Itoa(tt.squareSize), func(t *testing.T) { getter, bServ := EmptyGetter() - n := tt.squareSize * tt.squareSize - randShares := share.RandShares(t, n) - idx1 := (n - 1) / 2 - idx2 := n / 2 + totalShares := tt.squareSize * tt.squareSize + randShares := share.RandShares(t, totalShares) + idx1 := (totalShares - 1) / 2 + idx2 := totalShares / 2 if tt.expectedShareCount > 1 { // make it so that two rows have the same namespace ID copy(randShares[idx2][:namespace.NamespaceSize], randShares[idx1][:namespace.NamespaceSize]) diff --git a/share/getters/utils.go b/share/getters/utils.go index 88804ead84..81d9dc43b2 100644 --- a/share/getters/utils.go +++ b/share/getters/utils.go @@ -84,7 +84,18 @@ func collectSharesByNamespace( return nil, err } - return shares, nil + // At this point shares contains a row that is empty and contains a proof of + // absence. + return filterEmptyShares(shares), nil +} + +func filterEmptyShares(shares share.NamespacedShares) (filtered share.NamespacedShares) { + for _, share := range shares { + if len(share.Shares) != 0 { + filtered = append(filtered, share) + } + } + return filtered } func verifyNIDSize(nID namespace.ID) error { diff --git a/share/ipld/nmt.go b/share/ipld/nmt.go index 854d74587a..c923dc2daa 100644 --- a/share/ipld/nmt.go +++ b/share/ipld/nmt.go @@ -36,6 +36,7 @@ const ( // sha256Namespace8Flagged is the multihash code used to hash blocks // that contain an NMT node (inner and leaf nodes). + // Question: does the 8 in this constant refer to the size of the namespace? If so, it needs to be updated. sha256Namespace8Flagged = 0x7701 // MaxSquareSize is currently the maximum size supported for unerasured data in diff --git a/share/test_helpers.go b/share/test_helpers.go index 387db93a01..76f21f72ae 100644 --- a/share/test_helpers.go +++ b/share/test_helpers.go @@ -55,7 +55,7 @@ func RandShares(t require.TestingT, total int) []Share { for i := range shares { share := make([]byte, Size) copy(share[:NamespaceSize], namespace.RandomNamespace().Bytes()) - _, err := mrand.Read(share[NamespaceSize:]) //nolint:gosec + _, err := mrand.Read(share[NamespaceSize:]) require.NoError(t, err) shares[i] = share } From 3382a474a28b8c9d8ad14c5a7f577b0c983108bf Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 7 Apr 2023 16:40:29 -0400 Subject: [PATCH 05/39] celestia-node depends on ignoreMaxNs --- share/getters/utils.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/getters/utils.go b/share/getters/utils.go index 81d9dc43b2..4561245fc7 100644 --- a/share/getters/utils.go +++ b/share/getters/utils.go @@ -34,6 +34,11 @@ var ( func filterRootsByNamespace(root *share.Root, nID namespace.ID) []cid.Cid { rowRootCIDs := make([]cid.Cid, 0, len(root.RowsRoots)) for _, row := range root.RowsRoots { + // The below lines assume that the EDS row roots ignore the max + // namespace. This is the case on `main` but breaks when we bump to + // versioned namespaces because the max namespace is 33 bytes of 0xFF + // but the parity namespace is 23 bytes of 0 followed by 10 bytes of + // 0xFF. if !nID.Less(nmt.MinNamespace(row, nID.Size())) && nID.LessOrEqual(nmt.MaxNamespace(row, nID.Size())) { rowRootCIDs = append(rowRootCIDs, ipld.MustCidFromNamespacedSha256(row)) } From 2af019a9babdace503d856adda0130e28a307eda Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 10:55:46 -0400 Subject: [PATCH 06/39] chore: remove 8 from sha256Namespace8Flagged --- share/ipld/nmt.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/share/ipld/nmt.go b/share/ipld/nmt.go index c923dc2daa..020c7112a9 100644 --- a/share/ipld/nmt.go +++ b/share/ipld/nmt.go @@ -34,10 +34,10 @@ const ( // nmtCodec is the codec used for leaf and inner nodes of a Namespaced Merkle Tree. nmtCodec = 0x7700 - // sha256Namespace8Flagged is the multihash code used to hash blocks + // sha256NamespaceFlagged is the multihash code used to hash blocks // that contain an NMT node (inner and leaf nodes). // Question: does the 8 in this constant refer to the size of the namespace? If so, it needs to be updated. - sha256Namespace8Flagged = 0x7701 + sha256NamespaceFlagged = 0x7701 // MaxSquareSize is currently the maximum size supported for unerasured data in // rsmt2d.ExtendedDataSquare. @@ -68,7 +68,7 @@ const ( func init() { // required for Bitswap to hash and verify inbound data correctly - mhcore.Register(sha256Namespace8Flagged, func() hash.Hash { + mhcore.Register(sha256NamespaceFlagged, func() hash.Hash { nh := nmt.NewNmtHasher(sha256.New(), NamespaceSize, true) nh.Reset() return nh @@ -145,7 +145,7 @@ func CidFromNamespacedSha256(namespacedHash []byte) (cid.Cid, error) { if got, want := len(namespacedHash), NmtHashSize; got != want { return cid.Cid{}, fmt.Errorf("invalid namespaced hash length, got: %v, want: %v", got, want) } - buf, err := mh.Encode(namespacedHash, sha256Namespace8Flagged) + buf, err := mh.Encode(namespacedHash, sha256NamespaceFlagged) if err != nil { return cid.Undef, err } @@ -160,7 +160,7 @@ func MustCidFromNamespacedSha256(hash []byte) cid.Cid { panic( fmt.Sprintf("malformed hash: %s, codec: %v", err, - mh.Codes[sha256Namespace8Flagged]), + mh.Codes[sha256NamespaceFlagged]), ) } return cidFromHash From 56f2ff57f855c93028ba287294fa9f6e6c4c2999 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 14:53:54 -0400 Subject: [PATCH 07/39] fix: TestService_GetSharesByNamespace --- share/availability/light/availability_test.go | 5 +-- share/getter.go | 39 +++++++++++++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 1739e851fb..ae613fb8c0 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -81,15 +81,14 @@ func TestGetShare(t *testing.T) { } } -// TODO: fix test func TestService_GetSharesByNamespace(t *testing.T) { var tests = []struct { squareSize int expectedShareCount int }{ {squareSize: 4, expectedShareCount: 2}, - // {squareSize: 16, expectedShareCount: 2}, - // {squareSize: 128, expectedShareCount: 2}, + {squareSize: 16, expectedShareCount: 2}, + {squareSize: 128, expectedShareCount: 2}, } for _, tt := range tests { diff --git a/share/getter.go b/share/getter.go index f89c8616f7..6007dd9e24 100644 --- a/share/getter.go +++ b/share/getter.go @@ -48,9 +48,10 @@ type NamespacedRow struct { // Verify validates NamespacedShares by checking every row with nmt inclusion proof. func (ns NamespacedShares) Verify(root *Root, nID namespace.ID) error { originalRoots := make([][]byte, 0) - for _, row := range root.RowsRoots { - if !nID.Less(nmt.MinNamespace(row, nID.Size())) && nID.LessOrEqual(nmt.MaxNamespace(row, nID.Size())) { - originalRoots = append(originalRoots, row) + rowRanges := getRowRanges(root.RowsRoots, nID.Size()) + for i, rowRange := range rowRanges { + if !nID.Less(rowRange.min) && nID.LessOrEqual(rowRange.max) { + originalRoots = append(originalRoots, root.RowsRoots[i]) } } @@ -68,6 +69,38 @@ func (ns NamespacedShares) Verify(root *Root, nID namespace.ID) error { return nil } +// rowRange is a range of namespaces spanned by a single row of the ODS. +type rowRange struct { + // min is the minimum namespace for the row + min []byte + // max is the maximum namespace for the row + max []byte +} + +// getRowRanges returns the range of namespaces spanned by each row of the +// original data square (ODS). The RowsRoots parameter is a list of NMT row roots +// where one row root represents one row of the extended data square (EDS). The +// order of RowsRoots is preserved in the result. This function is necessary +// because the max namespace for all EDS rows will be the parity namespace so we +// use a property of the square layout to determine the max namespace for an ODS +// row: the max namespace for an ODS row is < the min namespace for the next EDS +// row. +func getRowRanges(RowsRoots [][]byte, nidSize namespace.IDSize) (result []rowRange) { + for i, root := range RowsRoots { + min := nmt.MinNamespace(root, nidSize) + var max []byte + if i == len(RowsRoots)-1 { + // if this is the last row, the max namespace is the max namespace of the EDS row + max = nmt.MaxNamespace(root, nidSize) + } else { + // if this is not the last row, the namespace is the min namespace of the next EDS row + max = nmt.MinNamespace(RowsRoots[i+1], nidSize) + } + result = append(result, rowRange{min: min, max: max}) + } + return result +} + // verify validates the row using nmt inclusion proof. func (row *NamespacedRow) verify(rowRoot []byte, nID namespace.ID) bool { // construct nmt leaves from shares by prepending namespace From 4a4be1ca8bb18379c84326a91238647a084ea88c Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 16:10:16 -0400 Subject: [PATCH 08/39] feat: verifyAny row root --- share/availability/light/availability_test.go | 27 +++++++++ share/getter.go | 57 ++++--------------- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index ae613fb8c0..893853ec91 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -119,6 +119,33 @@ func TestService_GetSharesByNamespace(t *testing.T) { assert.Equal(t, randShares[idx2], flattened[1]) } }) + t.Run("last two rows of a 4x4 square that have the same namespace ID have valid NMT proofs", func(t *testing.T) { + squareSize := 4 + totalShares := squareSize * squareSize + getter, bServ := EmptyGetter() + randShares := share.RandShares(t, totalShares) + lastNID := randShares[totalShares-1][:namespace.NamespaceSize] + for i := totalShares / 2; i < totalShares; i++ { + copy(randShares[i][:namespace.NamespaceSize], lastNID) + } + root := availability_test.FillBS(t, bServ, randShares) + + shares, err := getter.GetSharesByNamespace(context.Background(), root, lastNID) + require.NoError(t, err) + require.NoError(t, shares.Verify(root, lastNID)) + }) + t.Run("no shares are returned when GetSharesByNamespace is invoked with random namespace ID", func(t *testing.T) { + squareSize := 4 + totalShares := squareSize * squareSize + getter, bServ := EmptyGetter() + randShares := share.RandShares(t, totalShares) + root := availability_test.FillBS(t, bServ, randShares) + randomNID := namespace.RandomBlobNamespace() + + shares, err := getter.GetSharesByNamespace(context.Background(), root, randomNID.Bytes()) + require.NoError(t, err) + require.Equal(t, 0, len(shares.Flatten())) + }) } } diff --git a/share/getter.go b/share/getter.go index 6007dd9e24..9848aaacb1 100644 --- a/share/getter.go +++ b/share/getter.go @@ -47,58 +47,25 @@ type NamespacedRow struct { // Verify validates NamespacedShares by checking every row with nmt inclusion proof. func (ns NamespacedShares) Verify(root *Root, nID namespace.ID) error { - originalRoots := make([][]byte, 0) - rowRanges := getRowRanges(root.RowsRoots, nID.Size()) - for i, rowRange := range rowRanges { - if !nID.Less(rowRange.min) && nID.LessOrEqual(rowRange.max) { - originalRoots = append(originalRoots, root.RowsRoots[i]) - } - } - - if len(originalRoots) != len(ns) { - return fmt.Errorf("amount of rows differs between root and namespace shares: expected %d, got %d", - len(originalRoots), len(ns)) - } - - for i, row := range ns { - // verify row data against row hash from original root - if !row.verify(originalRoots[i], nID) { - return fmt.Errorf("row verification failed: row %d doesn't match original root: %s", i, root.Hash()) + for _, row := range ns { + err := row.verifyAny(root, nID) + if err != nil { + return err } } return nil } -// rowRange is a range of namespaces spanned by a single row of the ODS. -type rowRange struct { - // min is the minimum namespace for the row - min []byte - // max is the maximum namespace for the row - max []byte -} - -// getRowRanges returns the range of namespaces spanned by each row of the -// original data square (ODS). The RowsRoots parameter is a list of NMT row roots -// where one row root represents one row of the extended data square (EDS). The -// order of RowsRoots is preserved in the result. This function is necessary -// because the max namespace for all EDS rows will be the parity namespace so we -// use a property of the square layout to determine the max namespace for an ODS -// row: the max namespace for an ODS row is < the min namespace for the next EDS -// row. -func getRowRanges(RowsRoots [][]byte, nidSize namespace.IDSize) (result []rowRange) { - for i, root := range RowsRoots { - min := nmt.MinNamespace(root, nidSize) - var max []byte - if i == len(RowsRoots)-1 { - // if this is the last row, the max namespace is the max namespace of the EDS row - max = nmt.MaxNamespace(root, nidSize) - } else { - // if this is not the last row, the namespace is the min namespace of the next EDS row - max = nmt.MinNamespace(RowsRoots[i+1], nidSize) +// verifyAny validates the NMT proof inside NamespacedRow by checking if the NMT +// inclusion proof is satisfied for any rowRoot from the data availability +// header. +func (row *NamespacedRow) verifyAny(root *Root, nID namespace.ID) error { + for _, root := range root.RowsRoots { + if row.verify(root, nID) { + return nil } - result = append(result, rowRange{min: min, max: max}) } - return result + return fmt.Errorf("no NMT inclusion proof verified successfully for namespace %v", nID.String()) } // verify validates the row using nmt inclusion proof. From c0cfc7f08d0d0e46a685e778c2e7fdae39353b93 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 17:33:53 -0400 Subject: [PATCH 09/39] revert: getter.go b/c modifying celestia-app parity namespace --- share/getter.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/share/getter.go b/share/getter.go index 9848aaacb1..f89c8616f7 100644 --- a/share/getter.go +++ b/share/getter.go @@ -47,25 +47,25 @@ type NamespacedRow struct { // Verify validates NamespacedShares by checking every row with nmt inclusion proof. func (ns NamespacedShares) Verify(root *Root, nID namespace.ID) error { - for _, row := range ns { - err := row.verifyAny(root, nID) - if err != nil { - return err + originalRoots := make([][]byte, 0) + for _, row := range root.RowsRoots { + if !nID.Less(nmt.MinNamespace(row, nID.Size())) && nID.LessOrEqual(nmt.MaxNamespace(row, nID.Size())) { + originalRoots = append(originalRoots, row) } } - return nil -} -// verifyAny validates the NMT proof inside NamespacedRow by checking if the NMT -// inclusion proof is satisfied for any rowRoot from the data availability -// header. -func (row *NamespacedRow) verifyAny(root *Root, nID namespace.ID) error { - for _, root := range root.RowsRoots { - if row.verify(root, nID) { - return nil + if len(originalRoots) != len(ns) { + return fmt.Errorf("amount of rows differs between root and namespace shares: expected %d, got %d", + len(originalRoots), len(ns)) + } + + for i, row := range ns { + // verify row data against row hash from original root + if !row.verify(originalRoots[i], nID) { + return fmt.Errorf("row verification failed: row %d doesn't match original root: %s", i, root.Hash()) } } - return fmt.Errorf("no NMT inclusion proof verified successfully for namespace %v", nID.String()) + return nil } // verify validates the row using nmt inclusion proof. From f5155462b8151aea79c91e92668054769f2f4a8c Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 17:36:01 -0400 Subject: [PATCH 10/39] revert: unnecessary changes b/c parity namespace id in celestia-app --- share/getters/getter_test.go | 1 - share/getters/utils.go | 18 +----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/share/getters/getter_test.go b/share/getters/getter_test.go index 1c644dc53b..037869cfe0 100644 --- a/share/getters/getter_test.go +++ b/share/getters/getter_test.go @@ -112,7 +112,6 @@ func TestStoreGetter(t *testing.T) { assert.True(t, share.EqualEDS(eds, retrievedEDS)) }) - // TODO: fix test t.Run("GetSharesByNamespace", func(t *testing.T) { eds, nID, dah := randomEDSWithDoubledNamespace(t, 4) err = edsStore.Put(ctx, dah.Hash(), eds) diff --git a/share/getters/utils.go b/share/getters/utils.go index 4561245fc7..88804ead84 100644 --- a/share/getters/utils.go +++ b/share/getters/utils.go @@ -34,11 +34,6 @@ var ( func filterRootsByNamespace(root *share.Root, nID namespace.ID) []cid.Cid { rowRootCIDs := make([]cid.Cid, 0, len(root.RowsRoots)) for _, row := range root.RowsRoots { - // The below lines assume that the EDS row roots ignore the max - // namespace. This is the case on `main` but breaks when we bump to - // versioned namespaces because the max namespace is 33 bytes of 0xFF - // but the parity namespace is 23 bytes of 0 followed by 10 bytes of - // 0xFF. if !nID.Less(nmt.MinNamespace(row, nID.Size())) && nID.LessOrEqual(nmt.MaxNamespace(row, nID.Size())) { rowRootCIDs = append(rowRootCIDs, ipld.MustCidFromNamespacedSha256(row)) } @@ -89,18 +84,7 @@ func collectSharesByNamespace( return nil, err } - // At this point shares contains a row that is empty and contains a proof of - // absence. - return filterEmptyShares(shares), nil -} - -func filterEmptyShares(shares share.NamespacedShares) (filtered share.NamespacedShares) { - for _, share := range shares { - if len(share.Shares) != 0 { - filtered = append(filtered, share) - } - } - return filtered + return shares, nil } func verifyNIDSize(nID namespace.ID) error { From e81ed858af2361682452f7cb2a892142acc3e18d Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 17:52:50 -0400 Subject: [PATCH 11/39] fix TestSharesRoundTrip --- share/availability/light/availability_test.go | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 893853ec91..191aae3984 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" _ "embed" - "encoding/hex" "encoding/json" mrand "math/rand" "strconv" @@ -196,7 +195,6 @@ func BenchmarkService_GetSharesByNamespace(b *testing.B) { } } -// TODO: fix test func TestSharesRoundTrip(t *testing.T) { getter, store := EmptyGetter() ctx, cancel := context.WithCancel(context.Background()) @@ -209,52 +207,49 @@ func TestSharesRoundTrip(t *testing.T) { b, err := core.BlockFromProto(&pb) require.NoError(t, err) - namespace, err := hex.DecodeString("00001337BEEF0000") - require.NoError(t, err) - namespaceBefore, err := hex.DecodeString("0000000000000123") - require.NoError(t, err) - namespaceAfter, err := hex.DecodeString("1234000000000123") - require.NoError(t, err) + namespaceA := namespace.MustNewV0(bytes.Repeat([]byte{0xa}, namespace.NamespaceVersionZeroIDSize)) + namespaceB := namespace.MustNewV0(bytes.Repeat([]byte{0xb}, namespace.NamespaceVersionZeroIDSize)) + namespaceC := namespace.MustNewV0(bytes.Repeat([]byte{0xc}, namespace.NamespaceVersionZeroIDSize)) type testCase struct { name string messages [][]byte - namespaces [][]byte + namespaces []namespace.Namespace } cases := []testCase{ { "original test case", [][]byte{b.Data.Blobs[0].Data}, - [][]byte{namespace}}, + []namespace.Namespace{namespaceB}}, { "one short message", [][]byte{{1, 2, 3, 4}}, - [][]byte{namespace}}, + []namespace.Namespace{namespaceB}}, { "one short before other namespace", [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}}, - [][]byte{namespace, namespaceAfter}, + []namespace.Namespace{namespaceB, namespaceC}, }, { "one short after other namespace", [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}}, - [][]byte{namespaceBefore, namespace}, + []namespace.Namespace{namespaceA, namespaceB}, }, { "two short messages", [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}}, - [][]byte{namespace, namespace}, + []namespace.Namespace{namespaceB, namespaceB}, }, { "two short messages before other namespace", [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}, {7, 8, 9}}, - [][]byte{namespace, namespace, namespaceAfter}, + []namespace.Namespace{namespaceB, namespaceB, namespaceC}, }, { "two short messages after other namespace", [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}, {7, 8, 9}}, - [][]byte{namespaceBefore, namespace, namespace}, + []namespace.Namespace{namespaceA, namespaceB, namespaceB}, }, } randBytes := func(n int) []byte { @@ -267,32 +262,32 @@ func TestSharesRoundTrip(t *testing.T) { cases = append(cases, testCase{ "one " + l + " bytes message", [][]byte{randBytes(i)}, - [][]byte{namespace}, + []namespace.Namespace{namespaceB}, }) cases = append(cases, testCase{ "one " + l + " bytes before other namespace", [][]byte{randBytes(i), randBytes(1 + mrand.Intn(i))}, - [][]byte{namespace, namespaceAfter}, + []namespace.Namespace{namespaceB, namespaceC}, }) cases = append(cases, testCase{ "one " + l + " bytes after other namespace", [][]byte{randBytes(1 + mrand.Intn(i)), randBytes(i)}, - [][]byte{namespaceBefore, namespace}, + []namespace.Namespace{namespaceA, namespaceB}, }) cases = append(cases, testCase{ "two " + l + " bytes messages", [][]byte{randBytes(i), randBytes(i)}, - [][]byte{namespace, namespace}, + []namespace.Namespace{namespaceB, namespaceB}, }) cases = append(cases, testCase{ "two " + l + " bytes messages before other namespace", [][]byte{randBytes(i), randBytes(i), randBytes(1 + mrand.Intn(i))}, - [][]byte{namespace, namespace, namespaceAfter}, + []namespace.Namespace{namespaceB, namespaceB, namespaceC}, }) cases = append(cases, testCase{ "two " + l + " bytes messages after other namespace", [][]byte{randBytes(1 + mrand.Intn(i)), randBytes(i), randBytes(i)}, - [][]byte{namespaceBefore, namespace, namespace}, + []namespace.Namespace{namespaceA, namespaceB, namespaceB}, }) } @@ -305,8 +300,12 @@ func TestSharesRoundTrip(t *testing.T) { var msgsInNamespace [][]byte require.Equal(t, len(tc.namespaces), len(tc.messages)) for i := range tc.messages { - b.Data.Blobs[i] = core.Blob{NamespaceID: tc.namespaces[i], Data: tc.messages[i]} - if bytes.Equal(tc.namespaces[i], namespace) { + b.Data.Blobs[i] = core.Blob{ + NamespaceID: tc.namespaces[i].ID, + Data: tc.messages[i], + NamespaceVersion: tc.namespaces[i].Version, + } + if bytes.Equal(tc.namespaces[i].Bytes(), namespaceB.Bytes()) { msgsInNamespace = append(msgsInNamespace, tc.messages[i]) } } @@ -324,7 +323,7 @@ func TestSharesRoundTrip(t *testing.T) { for _, sh := range shares { ns, err := sh.Namespace() require.NoError(t, err) - if bytes.Equal(namespace, ns.Bytes()) { + if bytes.Equal(namespaceB.Bytes(), ns.Bytes()) { myShares = append(myShares, sh.ToBytes()) } } @@ -344,9 +343,9 @@ func TestSharesRoundTrip(t *testing.T) { require.NoError(t, err) dah := da.NewDataAvailabilityHeader(extSquare) - shares, err := getter.GetSharesByNamespace(ctx, &dah, namespace) + shares, err := getter.GetSharesByNamespace(ctx, &dah, namespaceB.Bytes()) require.NoError(t, err) - require.NoError(t, shares.Verify(&dah, namespace)) + require.NoError(t, shares.Verify(&dah, namespaceB.Bytes())) require.NotEmpty(t, shares) appShares, err := appshares.FromBytes(shares.Flatten()) @@ -355,7 +354,8 @@ func TestSharesRoundTrip(t *testing.T) { require.NoError(t, err) assert.Len(t, blobs, len(msgsInNamespace)) for i := range blobs { - assert.Equal(t, namespace, []byte(blobs[i].NamespaceID)) + assert.Equal(t, namespaceB.ID, blobs[i].NamespaceID) + assert.Equal(t, namespaceB.Version, blobs[i].NamespaceVersion) assert.Equal(t, msgsInNamespace[i], blobs[i].Data) } } From 62ab0d488d15b2ea97d0e4b1c973946431a665ef Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 18:30:30 -0400 Subject: [PATCH 12/39] fix: TestQuadrantOrder --- share/eds/eds_test.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index b33242109e..6fc83788eb 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -29,12 +29,9 @@ var exampleRoot string //go:embed "testdata/example.car" var f embed.FS -// TODO: fix test func TestQuadrantOrder(t *testing.T) { // TODO: add more test cases nID := bytes.Repeat([]byte{0}, namespace.NamespaceSize) - parity := append(namespace.ParitySharesNamespace.Bytes(), nID...) //nolint - doubleNID := append(nID, nID...) //nolint result, _ := rsmt2d.ComputeExtendedDataSquare([][]byte{ append(nID, 1), append(nID, 2), append(nID, 3), append(nID, 4), @@ -45,10 +42,22 @@ func TestQuadrantOrder(t *testing.T) { // {{9}, {26}, {47}, {69}}, require.Equal(t, [][]byte{ - append(doubleNID, 1), append(doubleNID, 2), append(doubleNID, 3), append(doubleNID, 4), - append(parity, 7), append(parity, 13), append(parity, 13), append(parity, 31), - append(parity, 5), append(parity, 14), append(parity, 9), append(parity, 26), - append(parity, 19), append(parity, 41), append(parity, 47), append(parity, 69), + append(append(nID, nID...), 1), + append(append(nID, nID...), 2), + append(append(nID, nID...), 3), + append(append(nID, nID...), 4), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 7), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 13), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 13), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 31), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 5), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 14), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 9), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 26), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 19), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 41), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 47), + append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 69), }, quadrantOrder(result), ) } From 4460faaa28c7318dc1c797386160b53fd65b7654 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 18:49:51 -0400 Subject: [PATCH 13/39] fix: TestReadEDS by regenerating testdata b/c roots are longer --- share/eds/testdata/example-root.json | 32 +++++++++++++-------------- share/eds/testdata/example.car | Bin 55235 -> 77635 bytes 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/share/eds/testdata/example-root.json b/share/eds/testdata/example-root.json index b687e3cbeb..a0528724e1 100644 --- a/share/eds/testdata/example-root.json +++ b/share/eds/testdata/example-root.json @@ -1,22 +1,22 @@ { "row_roots": [ -"A3I8MUKAXaEf7JDjUxllL5CGD0/uS8k2l3KpbN+u5fa3tGL1h9FSqZhCJFcZhzAT", -"IA74YwcC1tFMkQfD9sE2NO7hwDtjo37O1KiiptYPCgAQWQnv/G7bxu6mUJ2s3Ljk", -"ZskuRtu6YfK9pTqLAOsfLXbvjrvDD+80xoj/850Z4YGvmAaRH5vFXraZNWgEQNyr", -"w9Tz/Q7t/JfX7McKTWvNjhqi784y+nGCYXrQtu4jy90kx0irPJcVTXTQ7v6Xnjdf", -"/////////////////////1MCHZjf0ySoNlpt+h8Vb6QFm7BHYJXI14SMiNRgwA0K", -"/////////////////////2dOgrZG2ZT+KIrfjoPmTcGpqXdsdFZE6ZHcF0l+fL6i", -"/////////////////////7OJEeOYA6VsagglTnpIysAtyK3m3u4d8Zd66FuqX0+M", -"/////////////////////+hYZyJ10gx7Brp05g/MLtSV4z7SLLwGcMsXZI/Fgw0J" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHTFhSx3pL2TzSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA471vB8w31XZHnopsd0qqnrIfVzBnaeUwwhrSzNvBV0VV+fR488sbA3k4=", +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9ATJz7IJ2eM8xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFKeOh475dZe0/Sd7d/YZvijcIvVboK9IXySOx474M8uikVOpsWToXqKI=", +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOVNPdVhe/rBupAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDbUgoGqCZAcODs0JB2nUgKgyHosKtd27RgrzElkzpu/M7HwcZpBuN3ck=", +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADK2Puw1bjVnqxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvv3LXXLy+ptlfTSiXfBAVffz1aP1ZXnZX8OrFEcnGEHraUqFFHNzzFgM=", +"////////////////////////////////////////////////////////////////////////////////////////z7oU9k16pSH9Pjp6HBD9c15+R9f/3Gh8pP5EhXT+0hI=", +"////////////////////////////////////////////////////////////////////////////////////////EiImqkkAlJ9byWVpiEM30Xf8hGHf5fkCiLPK/J7tugY=", +"////////////////////////////////////////////////////////////////////////////////////////kJTZhKJhjZNXAaqev1YY7kPYO1O049gEPkQOA8uLwgs=", +"////////////////////////////////////////////////////////////////////////////////////////0hNW6Fc/UzAxUlvmEgrHY+p/A/ihwrb7p8x6DciPcFc=" ], "column_roots": [ -"A3I8MUKAXaHD1PP9Du38l5n9/iXzaDzWlVrLnsRE5zp+rEeyH2A0is+czwU/aHUn", -"D7uVznpBCw/S2nVDrzgGx9Ditcfzy/cL2Zdn+MBV31zeOgzCv+zXA0QP3SQRWXlb", -"FQDYNIesVPTUn9q9Ybq0VqDgprQbzKsMGrX+7kTlnbdOu434iOmx4P+vZVGjXAsm", -"H+yQ41MZZS/X7McKTWvNjoZId6AiHkxnGRsmYKuh4EvQCy+eEj19Q6Z5eQoMGWZL", -"/////////////////////1wS3guBpJRGNMLQMkEwgVOuXrTG3gUwJwI+nybYxTRF", -"/////////////////////1Eg48mqxsQejtwUIJkwrjEYCPvDYCRYm+dPXVitBCjl", -"/////////////////////zDz519rhl2FfQp6S3hR887dRSi6zN+Qs4PwIFdRqbxP", -"/////////////////////zARSBQBFxvGNpLt8I1qtbBOyEfFOXD4V/beDdU1kXPm" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHTFhSx3pL2TzSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADK2Puw1bjVnqxtmfyp21ILskj/RLG+SDEnchdtrB5SpmNwKuzvoUC6gR4=", +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANsHwL6Ob9gV8pAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPGTFJynN6qsCNGFem7/MTUzx/toLJsXscN3Us53aVstRjSncLITykF4U=", +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtgFZuc6+HTef8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtzesBmtJVQvUnB3winMTo9pRt/V5QokHHR50UFtFr++3pIXCkplNg4cQ=", +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA471vB8w31XZHnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvv3LXXLy+ptlfewqsRMxxtS1UajvtBS2mboLWqzY7FqE36Vke8SAjrAg=", +"////////////////////////////////////////////////////////////////////////////////////////ypfKr/j2SbwNvnS+kHAR+8QyQamzicQJnYRAvdWHfIM=", +"////////////////////////////////////////////////////////////////////////////////////////zFU3LQr1phGO10/Yld5kUmQTAWPHs5SHnChaVmis0Xk=", +"////////////////////////////////////////////////////////////////////////////////////////PvBBi1eB8yy3poz4sn6UzV5zcg9r0xjU8lmqgKRZFBU=", +"/////////////////////////////////////////////////////////////////////////////////////////2ejiT2RxUy1tyaJ8QBByb32SgB0VpSWQ8baEHDEJI0=" ] } \ No newline at end of file diff --git a/share/eds/testdata/example.car b/share/eds/testdata/example.car index 487bca4653922f3b43ea1e6639470f051c7a2534..6f68eac0bf9afccbab12ad576f409494c13be4d6 100644 GIT binary patch literal 77635 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 literal 55235 zcmaHxQ*>?H+HGUoPF8H&PF8HL*tTukSg~!}wr$(a-7hKop1+iH=1YBP?Pc~l`W&qA#Xa(^o}S`PlBY&=RUy56RD*ICFJ0dS5_<9r?6-VcAxJQVtU{}*%D zuR0Yh4nJd1yD5#u6oh}H{6EV53-_OJmmew17sF7}7L(CfdDl~nZ+8BA?lVnSMB|&p z!{X)KDX7wpGgn_JS!_E0QU3lvA4MSC)a`lV5>^eXH+)o^0?>>aG2Nt*<-o|$1>GK4 zsQ+0uk@0U5T}}KV58sXsIFjxyEp@SUR1rRn+d%*A?b((0Kg;!Di2JF)g_hd=y0AnyI}2%`p?c1mt|>7TG_^X-dNATdG^t zdf6Q-sRxg;sYF~|Lu=dF+cKMrMDr`xfh&X^1;YnDBd^aaR)#O-qDN8t{m z*|jMkuioejcvYANUW-XuRN0H!6HxK*WaI#$7YV71Nn4`4b^g}-x4rr-1x(o^)(Q8l zXCHQzW5%$n$M-F^P=Yd*fyA5Xe0{5GS8e@96sjKhq>9n2XVUelFZm)C0>W1Tae-`Y z-#*aTK7F4fEQF!pplK5>ZmxqnvA>~G6^PnN=wCIXA1ilh6mB=}hB8 zL#*T`077SV9F#ONCn?H|qjZ{)T!0GKf#`=D8x?ozuoWEunPG`NqoT)1F)7*J4*&$U zj7BvdwdChKVUTOipcJA5yA8-d6akqJ4%&uKmq^7f$QDkNx3KhAU+$olkl_Cs^z+F7 z&|rG+w+Y$=wMiE6(L)l$QYLTI_aAy=eqOFNV)IM58Vn%m3f+g!^&xrPmn5=cv?BRv`~R93K+JbecAX%bMlRCCjRFxT7e< zID*3G;LlE~^wg>wtz&hEgg3<|M^WzczI<1XvB#lQF2e1_$3v$w@G4v$o`*6ruka;~}xT65?R<7TqK0emiV3 zPQS`Cpw|e%9vWOFHoCuWQ<;X#&c6oz?E61FNt-8d`CX!PL@&bZtAQ9RK8B>}r4kL} zSVO#%C}idQllx(`>$dey`M@7O^Bi>&tV4PCHT{g{DHD8a06;8Fwno@r^xUU~zA9OI zV&ix=9D(wK>N&5tN<5R8h1KA>3oCul!)~*jbdZ*?!k-PR*NMuk2E+#V~Alg6z?c|*5N4;I5!W>ZR9Rx zuOl+h$1RgSibo$L+AyTcVbuna7jBl^0Pwq2dde!D0Q%lVGFVMnu)Op91|9&vC^d#C z4nV=w>D$FTwoB~Ysn1@oZ7eh{_6yp5MG2`+;P1@m1&Sj`lEQk;rxQ(yqeK{)_HVWp zZ%dye%5hgh8-kxu8m0aQXkWm8?2r?t~Nwf5Bx?V&lbbh830~*z?m5C2v zpG(j5alx*i@o`TblPB$^uW6{Iizcqhf$ZVCZPU6^QS=aOdxzsQB@Ec+YB}8Ms>H=E zBv7qqA2;p@g9o_@${90upQ45^IKo!k+OTObFvl0j({V-5K!q3|F%pEX_iK{?ZA(NA z3nrG=ZI7c+9?bR)#w;AO*NQ3Jp#RB$z=TAyh-&OAK1&S~k2Q6<-+54Vcr2Lw*Px#t z{~uZ>^+~(Z%ADUw(dgyUY=O3U7=pjY4)AK?EzOP1pGyAZekcSp%9qV`<3j|?uH2u? zBqx=u7Sp3+_})?Ko-F_SToB_tw?1g<%58JZm+;)UMb+2o&%IvK?K@vqQppVpf}#y_ z{RoJPn9E}0831Kgf$WBl$+zz&!U{M`6hFLB$Lrs3MbdimU`F4=@ajp|g|cd+!WDEo~RBoC$t-*RN)vwHpq3_o6sopl>?-+*KBE&)k-HoHt#9OPKZ;|;66JCn+U zI&37$)nhIc<`3!6J`JDQN4`6qZ-dNyXEB%Q8dXjL+S({JvtNB&gFUtf45m{lbLsN$ zv0QrDgVd*eoer9@4kwir7{61q{B4N7>(Ta^K0TQ%?S^^sdJCVIak&l~#MhbyUrVhx zg^rI>oE{m*Y!?tO6}p+}kSLr6!>XJduuMGM7L>u!rUyjCO2IS9k}4-PzPl2(ms(C5 zpN)^7HSz`F*m{CnqdvmGTL$mq(XsC`YESP$<}n48ltWyR`3=hl(-TMCjFb&oHy97< zgBzK=$3$_8ah0GiP{J=*Rs{M*Qct~VL{4K5*meIx%JyWJc5y&l;E8}9ppU2>cdN)2 z9M^&ma)}G=1SDFgW6ZUc;;LDZ+3h~I)9im!6EakuL*btGg&T4*bfaf(R+ATys%u`a zkLIH8Knq3bPDAkhT3=C_6TNu{mJRvWpr1b|KP&@Jlpt~oCX?HKxk2Zm*HR+Id=8#X z0!7^%Kxj|&3HizWux5_ocAZA3gP83c#$emhXNXtK0ZgPblI za+pj1xA0xJJ-7^ky_s6agZQ@}%v$60-@=PDB#@%MG&P9z^C3$9wGUWc+yQsju_j}1 zOSuWM45I8s@r8-6v@fd@3)`5B+LmBujOBz#Z$9GPY)Z@ah-mtoC~yjG_=!`8JQS73 z@l7xZ=+zl0NGo6pVquPWu&0m~dqV@WRA&R6-^NWmXz93Q!HF~=#*}+GcF;)dH=2O& zOm?@HdIGbG7RwM4ov4Mr29R)x3_DkoSk*;y{h13 zU#!F;IBx4+C+)3?0BT%JeI|XpXbmFJgl#r$ff1B!%MPSrjnu}bw(DXF{6l}S+qrm( zmun^>!hI>ybmEc*uK|k&udp4Rb&oMWEVRy7##QM;#bZ?Y6fdp517>|!vo|Q*Hej*{ zwf6yrXraRwUC(zv8^LAb)fAhjiC~(YgvUVm-DM*)5ii5TPVGE%MSC=Z+kGx~+eQqm z43EEgYI;5-;U|^y;(PqulQMj^Oknt*@8aO{8X=da**BV=U&yJg5dG;`-ng@Z{r@$H zA_kes+PDKt|fal=^2O;<)y0ke!SC1|oUF*e5&g)M?GQ6G-Es*LVgKkX%N%8c{$ z*UC?^HP!p*k0-^8<8QjhPro^;wH?`U%tNC41Hiha+~sLa@V(1%LauI=FbSUnCJVpl zITuat2^%OSE`7Ch6GXi5+tZB3uO6u^!$?UA z7Vje`3r1YiEVy>>7iVg8NDtb-v(%4-gCY&xUV=m|)bzB)aQB!7D|#ZNHH`plr38htr#|g8bG*^QSD}&|1+PD$kTV^{`r&pp`HB@@l6N}+#gHy_1}?1L&s1%6Yfp$^H5M@ zq~|(rzXet^K=Gr5PF|ZCvW*iVO6-ba2=u@UmX+S}?#f@nf6<2p_=F^1#u1I{r z!FSp*6R(32pG;iL_`E%DPPWkFUjRk=(S>7s$fgr9twP3k{y{^XjS? zlug^HE#KSxEUBXSrLLvZzgcB~^EyVdF~`k^Q)L=)TIo!qUr z*@tjwU(DUh%lWB)@>bw`{sKnqX>OdrE}+~2mw_}%SGW%4>B z#$1XaXx&UmTdK$WMgNbG(Yh8bDq6A&e2^`7Bhji~o2&ui<4Do3)m!T==M-2PPW6aA zUNbEZ>8vrtK^(WO5XS`QmzLJIf2n7o~- zd8hllXl42Y@XG$}aD;W-*G|5Zi5N1WvGI9XApa?W$Yqg2f9*{gACty0yp-) zj$t~96nh$9C0O`nswy?Hp^4nT8)C()A$gH5ZgrT@^!&URn<0(hxT4 z9#pT>#!Jiu)c5@Fk&mqdkw=T6TCSI&5r&5Gve|rA{XxD*FBGr+}bLX|<@A zl}Y50=ya&&WfN|XQi>PqGf;I2jsbO9w<5eDT{rM1yw%1bI{mN~@B2g8aI5Q*x(Yt;zJFMfjJpCgwFB~2gzDe*SkpvI!zS9ALm;GTb!RGwMP$3b!MQUV&NT$XHQ%8E)ofYz0&z=CkLksR|` zpjDxgZfBX!m`M0oTPNWl8R?gfQA;tg~QEw*3CA731l9}nO z=6<`w9&RAEjO`1=*W~TM;y*p_55(>TirIScL)J1Uh5zjn9&8qG5nRe33uvh0dDJZp z?l??UYjzpu68(Fj_c+~)8TDlsdyGz5$^~$iZ2TGQMA~BRP#%;yUW>mqpHJk6y`+56 z1ej=>b`m84(+otxu;PjsX67;CIM}3)#HWg>09Mr%%>UV7(37X{VxZ`Qh#Hs$YoS^t zVWxEm`@)0LETFZk_`Ik@`7+%Z3@AFL!L@1h8>S>Wq>33%FDE?g#shQ-UN$dohzGSc zJpTpLC?U6S;iXR;B6Po+8DS_uW00@f=H{{+Q;IgxnVC(k9*io+#bgF?m9=-_V5wFu z0ls|E$dM>CTe}d(TcZX8?ae9643zsP zZ-d(TY%ikC`Bn&`5qa?D4sZE~YWxFmSo{fqV$#2fV8)JBr1vVe^r1-I$SkYeU5})$ zyUffUO@zg}ZS)6S3j$RCezS?$4qplyj$W9mpFLs~F+Wdc>ZTM_L3%t4-q=y<=xw+< z{h4k0fXHkYfQSSt;bQ9norAAarjjfia7~@Qi@d~FSXT8)byOZ$0(y^IIbX09ODS5= znaWZClX^KXB$cdS)DGl)My4SqSOAw+o}vMGKCPi`dEr*a!>5zP!5tFlS_mFOQUd*Q zHE&%P9mfVE6nMicJ&<)m9ISYjN9;ylO1n@p(T4^#PoihRtvB!EFHIun#&o(b<_Qyv%Y$UI z&?uyuv{2_fbQvZkoEp2{2X|q283n$2ROEz^#fBE`Nw;EJ$xo#Gi9tD+qy;x2=i*-z z)*~T{&9bOhC3(xqCR#mTQJ&vdUc=?Gi(JQauYPD#=_hJ98CNA@)N?Pf-XZ!-plW1= z5O1J*`65b7HG>s57>jQS6WqbcorA%j1_a-g8ig9Xqz z!nx6uo$A04rC-m)LLD#yL(%&4uuZ>8eCQKSlCmZgC#cEhJWzY-Ky z30-beeX(iyIq6$M^st%t^|E2=bk)BG{oEA(aHTei*EkBepG0t__0-_F8GP&7q7Z4W z9w`NOv1clv;wSe*5?;S3uk||CMRrwh7|w3lBRb-qN$cHD=U~1%viNc+8dvRFCO-8y z+fZxe@1xSt)QFlQP8BJT)G-w~^QVeu8uMgq%JID0N;R zS+h<~0^C0e;%)TT7NO{&?!PQSGn>ig zWtz1M(_;y2mC-H|P$KtKVC4i!IJ^KpU0NJNAx0CFVkOMV_}$P0 zpw4u>1~$GBU4L7BG=C`j*vWt4MCpGUf$mi_7-ctQn92E~{}riIfd!oLRn z+i?7-lM}+LBHQ^LewEy#No~ns$_Se_VDGsP{1%wO6wk1^vioa0HC4&wLC)i!A zt8f97`oy@BiFNC;XpJRR;jD+kmuL*|^jmbKo3x#Y8p6&PqX{Y*X+T5%@_B%XwB6o0 zLlC%2jXtMSV~dFS>piY_Q)IvHNRv^X_d%(q^FR>^5A}vAlD1IWqb}cV43;jw}pXPBDvk`eo zW2AZu6xkP$ik9(xmhHV;cfgFq*6(Bzw)z!hyJ%b{E`_37s{tj7-*V|PZ;k%6^N{-@ zhXWw0I23AnhWmh$e~Ys=zRpX1d%7<}_X2M(xKYPl?F|7 z*<0563cnVE_^cE;M3kLw0?m#QqS{}tN;Oc^YJn(&6KNpfqgi#o=PCfO3Q_lXrd7@Z z@-$|!Q^th!-Waa`4Ng?4k~eV~Uj$=YMnWa!ScF{GNMhb9N(Q|U49HQq;8+d)#GdfQ zm?2dT)2eIVJ(AS060|c^GP4}BW5+1^`(J~8uE2k26Vbni5Cxsb?L6E%p*6YGggfiC zCVpG0ITxb+AzNuxITbe2n?CIQ!%g z@UBT?Zq-P4mslA}(r|$ACz3uBrooyC0^?93nc=3G7q^cxnf>>cR7!37F$9PX$eP-G z-9@38(pe^GzsmBfUzA=IM?3lE;+h;w9rM(t|XD%cg5V~gN4alt~F!Rx=MN!ePM z?`kdWBwKEYutZ=k9O=tLe!vV{VO@f)Rbva zVCHPTn+_V?=1tWvcgZzegQ?}6?Vns}AlzIpM;4O&Wg6A55XKR4%qm19-p&jzM(wLZ zGohk2Bx~w0;xnR}{F31&#!kkUJISseuxZ8dp6Kg}<2$`L~vz>d@1GfCx-bWTFU_b(xKNA}GR*A3G%X!|2lj65E{p#Lf!o zUxR+;Abu!Ok0WAw(HP4m*TSOAx+455q)DQXIj`K~Q3VWiaq-Vj?uSmEp(Gu0oGKTc zrMTVS6QyO-leg;xneD!e!>7c-^3-J8!@H7@;_8^MJ&PaNI`=7O<@E5^o?mx0ZhbuU zR1UD6(Ay!{@4&P9dS-G026zScRyJPepFukI{%%37=hb#{PV9IT7llxnt&m57XzjA8 z=^vDjunG~f`lJnr7Nf>Sx#}r+-Kt@8(Q|K^A=X8ZwX8~X2EJh{<=qrstU~a(N_9Vg5G0;M3kRK zTO;s*_Vyc-{p-07um|xCMKGCi`;ae*6}wBZ!b7JXEL^&IPdVzRewz&^GS-rjY$I$H4+ zHTy{_CEV6;%Rt5?uFzN8FaXyz z6GR>Q_kFGB>!s3iFf=*hLCeVb2)T!r z&Z2AT^A=&i+?-}5E0z`tH_cO3BWSlw6|Qx)f|SH6gaUrhddmZ-PCdc53Tfo)Tw+B%32tn?LD6b7^{WMR(?nXs{-gL6hreyfC zL9FShjW^cvPDM$MHrOqZdgjW3=}8qCr_AB)2Q!_wY%CiJ1Ow!FPhh?uC-r zvi}dkfuzt#vE9BbpHDi^M$V2M=>UBKeSU=&XlG}2ohvp&D_AfGmGgM;8HnU6Sx zy)V=|^?Y)PQ-~)23Tud@4E&LjkU4GItcxxRo}Y<#UOAvue^tk(-=^fI0aYGEj=h~TUH)kTtzTg}3j!=khnP$|NO~kYCo(p?&9)9PL>&();v)&>E z%6{pSE~Oomc?su^XHDg7o#&w!3<4!Xw1-7#&(zHp9x?@Xdc=OY$2o6e=!<=)$(Jpr zv2jZ2n0fK>JG`nX42;-vyLpYV3=0|K36~;2D|U)OXoNn>;Qm5dJ3D}8murf)6{Z+( zQstBPbF7CfwjX2=M0%9lfMFsJ>;mzPX|WoRk^p1No{aV;4MR_7!LT$9+7LkytN*lK ztNYm-UU6$iK1!)>Q`uBC0iL9wpgc>dX^ZP%Zv+hKj`gX}B^~3)5?-6opJeR&rh8CI zXZ9|ir$X;Bpg<%NfV5HR!qi-YBRlyR>%-BhW`;eg=Gu0&7ViU>3me03dS6it<0S-~ z9vEq1a0{U-{VsdYgKOlv5&)^fvpF`NbQFln4f)Lkp;hhlk!}9r?xTrHFWM7X&H~_9 znEaoQB^7kub>gcR14``jN=b8>5s9fVj{P>CXv$0gx5WQ$Q2rI~U?Ztg_>GP-OBmy{ z_d7!PBBft62<;V9Rt%?`>yJT1v{6JNyoXO=a)E3cMilqFcVvtw8PsN16oPeks1B&7 zflA)$??i2pJZS?Lbefa368-LIk!^PKo^HpBegkPF$IJ>T1H9*U^BXa%*jZ zv&rF#VTfy11{pI%l}}1*s^LdU1?~CY)TfnE6?(>2MfT=5RM2el9=CDB;P!rNx#wf1 z!-k(jJiLA?GX41t{sLw>V_YWE;l^hG;`sh;^Z?7sHL#9s0@#|!lfeolJ^MHGfQRy; z2o&{e)fI}{=8yUOalptyY<2x*Q3Lf$fFP-H0~Br_^|!H&^^2M(etiPiKU za?@K^XA`_ODBX$9mzo9Pzv1I~J9&|u8OL2$@VLxK{y@nX`bzQqEfL1E7P2=WpunS!ba`S0@SwkT%MU+>!I>JS11kY=o8CdazSr-lVM1WMFQ@s8qXo zo{biiScMQt-Gao<JlG#rMINnUv&p%TbKU`qXlFZdif4lEef-N+6ID55UMhM zb{^5b#G2x>MyvAhPISHYl;Movk(zU8S0ktrp7M8NW!ueXL&KeRIbX}&boc=TF=WLHHp`(a3Git?IA!2$z>g$sP z?G>J7qH*#qT16vGjo7A}rMFiiHek`NBxO=Vbb7Fh;d@cR(ayR8SPEf|bSUCvI1!9* zBfwVaMW_@o{2zR7#;wnE(GTYYceO4nAQQ<2zv1=T>PlQ#t1K@b@`mH&kx|98c=14C zrc*$^N^G-|jxD7~JP4NGQMCgv;xzW>{mKl9j{^x}Q{Sa7ypm;*+bf4tiD)e~3s$gUEre{gM_Yu05X3^kuq$}4HJXj!o}~BB6m~~b?*&aR z=Hx-(F#k3jG!G-&A0kK;<=(&dpm9Xvdl3oPYTK|Z$vX)#;OEdu*HAp4<2u-{A1#^I z%~3UT!!@trL?3`nOZ@{=s27<_6*9hjG+iR7!&RXqUtAcYmRw3YegEHd$Bz*|oXgTi zx9Ce7K2`=BguFX!wLuH@90Q4-N1fN*~+0sFQdX1av@z3 zP~{cXwp)Ge{hI6Q3$|d|>pqSxJL1v6KIhmY@u|_*NFutWkN{*lm4k@a^n-@K1g6(^ z=*9aagfNt_P+HtrH0x(A7qlEUDHy)oNK1a~=$3SRdI{Rfys2E{j)4QulKJSY8@+Xx z{sYofWVoq+x%*#Pe4Ta z_m_W2tg(}Yh;Zd+4wSVz7f~A;06c$jSbnUyrxYH*nAqohppRAXvS7H=v6Kyw&I0$< z4&cTqhuXAnqv)y87!v!hlNQn<7@)C4w6|mzK+To3xtm~4!cK2^S;J1H^R%f99ixLI z_E!Xv{qI^2Cqy3m0Q!1M-pewCsa9gT!=B;}DcV9`U^a;X5ONnV8CksS+!JC6CR2+u z-5!`oVBz7D9t;mws|mq6Wt-v>^pakQLQnx=tl*HN@LF6ifS3~>Z_|~2p~nQk7^+bq zFuBw`T2Cm5Fh;^{6EGzkuN;{D@->?Oz6T*!SA$MT1NHzY{LvF`-@qB9^ofB`A&UZF-8X*2j1UGuv?XQ7on)^` ze=5}T1L-N!X5@EbV!1Gr(O<)z(+zeprd(ng00)`cR9I+Tmf2OVfm8TS&1$8HhGOE; z)5+m zHEuyNUcRVx0E@*`V#gU%1&BAYR4{*#lH?`>cDeV1SRq+J#Qhy!H1X0tpb?qOwE~kq z%TnAYP0jd6z?AwMhM8|UwSn!trFb-a@Gq%|3Okk*M+TGVCJA`OJO2qZ z-3VMTi#@!FEB;-Up6RhFom#W3TQD@}DU5)vtg9Ip=raf} z+5sNNqPD@iY3DJJstNsZZye&ievs*m^GpKt64LSPoDP_?#b{_9_-8gU;lhchy|W~l z?&QB4#7U}QzKLU(S(TL2*QL8NX7jSBHW1WrE@ z_TN3sPFMDrGyR~G#$MK;c>?1A(_*kUQ6m<1zCngM-iLrtoM0qYIIou5OfSrRz9e!X zCx3VEJ}Sok45B<#bm6Kt&bmHO<;xYLH-=y^_HiDXK%MuIyC~zm`12R&l*m_XNX~KoI`;EQEqD+}6G8v`r4pn3;PEn0YKbVo#+4ln@BF*iOxoU=3 z&ZisB>8;S#^Vzgl0eZb8}|5Il^W7adl_qyu>PE}E0hWno-?A60}A zfMqPch5!VYwTBw`nJ_1t!u9lF83=3*_9k~e=|HpmcZ0lUpS*sD6-OD)cz$I2H`vyf z?WxT#urP5)TpM^<*!%w&B$fJ022*&3%q<9k3}2;z*a%Sp@q8> z4Gq#wRr>yp_NCBRCl-aIKVfg_+*A{3q$3}aDiInSIC;YxA^!fECc?&PrjfDnG<-}G zhdsDMg7iS!x=7@hnk-0(4fmN|O{VGq85;q=9}Vi$7b?7HY{+;i;pHx_m-ED54Z}9oew2D9 zvQ~YKZAQL4-?$L|V8@1dcv(%MmqZdvP1qRe0U@o|TxGt*3`W`TXHOd{Ac&fCQ~F|4 zsP}?1Q49Sd7^!)mi>_X{YF>pNPiNy@V6fwEJGr`G+GU6fQSuv$mo3Aq^gsLj}2NfVuGSk3lhG63`*p zDm3QMO@w6}k==_;M*`h|_TE(_7dp~YU$e39Oq2XVLwdK2L&T~}f8bFrSy0FeJuL*( zILv#+bOv>dlZ(UunP$J`%5iHA$qCh@mUHgbdo9Bra_?a?^lYnIA-4QJdSdEOsJx7FaxFp+*3$(d@D-T z4AcU-Q`ch0!IdACvu?D?kPJeOWt>VlO_fVa_33gL@#~sJ7@_ltLOrS51EnKjD0PC7 zx?q0Wok0kUat;wS(CdN$niw{q-O^zCqsX6CULYmmqqM?_QEwsANgG8<0HU@FHG&kf zLc|Mq_E2nmkS-jJ;s?ih6)mp8*G$0`5D-H}7ft4Y<(-WoEtWuRcd8PSXDVs`OYxhJ z{k(mEu|r>XXoGwJiEo4)?$oYn@TovL0fTh4C{SoOxcWLiY#Z*c$NVG*j&op-pU1+q zNp_er4mg&_h*xoH8-N@un$u<6$244-0)?3Ao`=L%E<~FCYtm_EiBI)&G|Po+GBUla zIoZCLSt#_dGzdqa$cO{^I`qfZ8b7NS+n-{ zuh5GfdEe@-!yEtBvHE@!GvP3kgNPMDav+u!q1DcnOo^)#V$vIdb}hf`K1c~8jUUC?E>POD_pYFH9}X3U+=12y3B;=#tmV#>*6SSxTtIR@SvkOktZWiwlz3$U?jeoE z32nro%rQMGwrt$ul=Sg7ggC)8{S%o;M}9pX9s!8n0R~ecFgkYLfU!?dsKKhld^AHI z`)?V}eK$m3%nQcAG2&|#^VYF))vd|62Tn|uPb^2jfROt_!Ji)P$kJsk;2Lws#wuq8 z`eJdOTrFF!>7EYPT5NVlVkVzGz&1Cs1C7FPG-$OQMD82>l_e3Mg5EYS228K^FjA(n zY%>Y`9Q@Uk2@}O&<2xbL$++7t3JBwMJX?G*9t56M?%J$irbV zF;t}~<2DI=LJ)kE8Wt=fhOMvM8LO?3^r<&V59wn>;+8kqp&_k(sI_~#h6aSvEU^je zS-wjhn*ZgQ?YRxorKMX-iupNd|HwmNpQ6Er46LBdn;lv?S5ItQDT33317ca3I%BLM z`j(OmQytX2)q9u#jxxpRu8w};5dvlSyYj{6H-su`b-sS;GBw#=aP3W{`yJtL4ICL$ z_pTPw3kpW!)L&9UHJ(v#b!nj<@{t^_J1Y2)8?0WkP4PwRAQo-5Tme~hbAXj^McVP3 z%09|dJbS;EWX zx6ZyM$mV3~9`uMV(#Jcf8q$ix7bK~!WKt&P38FXC#r8@=hw{~ss*OZ^=~TOawcroH~~hhM4JMO;82(kEWLu+&B>cDXZLDs*}!028XUSEW-l=w zg_yUr1Xrl{tgy1G<%Mnef`vd`H|F8;CyJz@%1c67w!SVDa98}Bc6(?#K{ zJ}%(1SE1CTCrNT}ZNjZ>Bu))|h_X}se=?9jI4xhn>tOKOfRXWZu2=qAV3Va@zr35F zU<9uvZ3O3|cFN*aT?2TeRQIfn)tKvQr4%#igAteX76MWq0OW-Zo1AH|8u)0rmdU!Q zh~B3bDMIAOLLrumlc4Qj*573gFDj!{GqHzDej%g=wb+j5>4mHgMgvu3I8JL3wGP-} zzAv7-@sRVA*>+&iCeZeZdUCiNe%jm-?N-O0S5`ojA=?S+x~;=CRWlrPt(m5^YWfdU z?boB$c7%mR-Vd0|b~}bs*AsEfWf^X^E+9K3%hM+AZb82=*@3Hgg~k5$b33iEwm!te zpwz?d6lkDEZV3%xe{`X9@Q6#ceP&fGKjy6oz`?8q68I=Zwy z-Lfo1!>yMN|6@>~L(F7OJ5iJ;w2M2{FezU46^oFW02}InoXtwRSp!h^o3h5kdtneI zuf9Xb9XK1&a-3zk!-I>YOUpG&pI}jIq)dO}eLl|c@a%%xHz!u0ZS{XR~U&?~q^37r|!`Qx++JcX6c}tkBp-uc*}o;G_s>qlHZrf~L&l*a7;d z{t1ETn-}z~@(Aja=nXYrO{~h|;#)#h*^Y|dbX_%&Y zB7x=3Fi{VrN`mj(*Lt{V_0Xf$QU_aREK;3rRNOUH#j8ku@fe0%29RC?CEe`Gd$Z3o zc}KU$BK0O}Mu%%&*1AG4yP%?*wPiXEHUuSQ7JZO5t+W&Op@sm1H+&-z zrQy2jZkHXcelZAw&onrD+H0sLbSh?&vntyB|aj%pud=s^sStY`yiG?kf4#`htx0z3F`^Jyim%R3}b@3#^oMDj93sOT0 z03-nrr2)CJl|K2K4+%cFMv{Ka1YSV=rpjI7{+>kCo0S3h1SHpH9fOM22Oh3%fUi7x zZ+q-g<U#I3oHf3N-${^)vA|BBl(nc#}>u*e(Bf`F|&uF(DYk#vrnuIx4!2^A_%{&JOA=&9`}H# z>A3h}s;9pNSicYMx~P7ev{!JL3sKZP5$>B4{yT$KRp5B*Psz{eyaHd0Fdfr#!#|r7 zK=tu^G~uZH@_#S?6~wg&E$c&yyb5Jxj^&<3PQJmYn_V9MaRhC)>bFoh{`Is^JQwH< z0a5S7*fi2#;E5}{E)i(XopfF+q%W4iGm;7*y72PA0XFpGE6BwOWSJ1PALsFDVbwS` z?<^h(`3E|p?@33)czCQES+gZpozu>L8v`3tzl_$~12MaUm8$ZqGlgQ7nlOd3P56|) zFM+KY*8qDGAzKn%q6TEo*4xmQJDzY?ypZFltFS_j}E_tu4 zvF)T68+HLT3b>itdoZEL$zh^(02Is0D-gags7ipTeCC@bcp31o>O#jt030W0|Osw zpW=+ra}}H|`22uTXsz#S+B$xCF(id*`zg6qPH7=c17^Gxg8B3u=K{~c<5Cb}HQlzL zTz5Zi6H@RzpZx*(Dw_9o46I8Q)`y5^{*mb{syp+qRIQKG{$ zTM-jd0VlB8-+ax5rRf)(g`ycxdKzWYbFY!Du1xnk;w>#B$#38TANb^ib5a#9p~=f( zVU)&3nY`mFnXdR~>nbN_DA!gD(47;t0{|)qzJQ#x%PLD&zg}hQ(}IHu@x_w7X)*(ZBg+E$w-GV`JvC|pj;*8>}BGq;q0+w zn(*;M+OQe%YP~M_wWb5x21k$9(qcVvY+rp-8aNGx!4qD5;gJ>>Mx4bw@kjytmyOr8 z6$+6RIOn|XP3^ly*Sd7~X+?{lSwuFLm}YCP1x{v1f(A2PWimcKRaU1lug#BkA)gV% z93Wukar1GbNCbMKck`{)i~D%`>3#1Dy}6t`?U7G6hCazI1t$l_isB=$G*r*r8g~PM zs+TGwEh*PwTdPo^4OH4D&k(pkf|O;p3yP278l-TU>38@3y8~HgO|tC-JOd%HVGZ;RisJbLbkaCr4))f=nlP zdftU_>GziOx;PB2hk6qDR2++N@n#}!K@2aYCz5{_F zC?0{%IY+r1tY0W#a6LMg{=_3A1aFdIS5-tviN?&1pK;{>7KG$DVsb@Nn#zHVaKumQ zi#S)QE1H-_T6t|P1)5Up^YB*?e{~i3w^!TO$v5t?&GJ1WTo|Y>3ql&EPTuw(E5lN= zVMJxm55W6^17(dNaU|7p{%PVdGpU{vCEcZMtc&~EP}b^nfV;}P>(y7#495vJ_q)5m zHnTpYp7=Yz71zpViKQ)A87IOH2;%5~i9$8M%Mc$D^_xy}2`85_2mbci^oyQ^pZF%I{(-LK(c3>4%(*VJdXbTnF~uj| zF1I8O@}u4t?t$Q3zUpDG+umG{2`L#9)Ek=?4m70iZX+Bt9|eP&hQ%1eaC0Adc_m+&p*3DD|RHU7-2%_^s0#U(B<5iDg9(^*)O5BY{t7rv2xNGzMr& zWY#J4S0nma&AHT9-THmrJx(&DyjX&(h`~O51S}3DO?~cp=N{hORDt+;t_6N?Qx&W) zu~bG--agkUdj&pxNiN03JLW{nQ9*h~^O*!8`%6pbuS9rIvQ>1JHDz7C=HL|PHKSo; z+eGkC_o6qyy`t}slS9$w{b4jx;8Ww5$f9S4?NEVFw>o5_V~Xm=R050+nC6354T2Fw zO?u9lkf9SJ6JeG@|1HQP?yNrrD5H>y?qUkS%UoxBV$`_&K{RC?I~ai(*dzO|APZN^ zt_$6|N168r4zBsIL*=`bU_{zFJC1j+)%}?5d^Q7&Yv~6N!Gh(TLMc1^!37Ai+ z|1A)soIqc;7y5%{P>%L?5_aU%Wa$_wCqz69Wg#2ny#g{9W~tP)lj5W&4X0M>Y?2Ci zTK@2zYg!9tCFl&Vi$p5XS!W6_zXG6O&WkI|+~gEHi?YIhBDdk}Ml*aepCqlPagB5UgSzvu`w+_^tId(a`9T(ZfzX9k!YJ_PTK`i9Q}fK1s$k_BrB1Mkt_|rKY=jIa*9d-?r{fBLT4~VUd8V zk(z{G&@Vp|#PoH*_ zUO~(pE7<8CjMYHYI?mU#$t`phij^)x}vip5oY-(mP$FOZM!-wuscke0)Fq$KdSzI zt_Bo`MBdwC+fl^3k(!$d(}8E##L@Z=jcgJHZyPH*^%(#Kd($lXt$q3dXqjuRwz<6S zI&FJOuu@S5Q)u_@s9vg*(PSg_YN;qF-1$(>Bj)^7b9F!T;-mF_{=CZqH!%Lgpx%#$ z+^Z*N6{qm6YOcc(veM9KDW>?VcwWTU*L zy7eO*cVgK#nTYB`LHTEHxqJ1XuAp+reVM7-+;WbgKP?9wDi)UW!D{58AnS6oIpO!R zzX6RRjAS#xM{+byfHv-rE#zYe(pn*M;)bqnCwOx>X)ln(g1MaL=RD=<+M>?6@i#4} zB`F`M8Y-f>V4_S*T7XcZf5&yxG_Qd0jR1*u^L!f$*gJ)^KimN?e3eqQV;estts|OV zo-sfnd5Q5U&5hbS2<`DQyiSp$Y+?7|FYE5Tv12isYb3T8@GNudw}pKT#8Xs^wLrs! z9m|SPM~!UJ$0XV(v#{;&9d`|ge+%l~pb82DGI~NNYfRJyOZaerF&uEKd?J3HKsc_^ zHN5#N$ZY@!QGzJz+7^T0GxAlYlAP_T8x8p9DS54Te)B6J9UF74o2~bLy5e)4$w_kS zN&_$_zb6&b+_HFZGx-BEq;wN5yA3tNFKvloRAgF`#^e3Bz;O&waq5}ui)NS6jaJDn z5Bpq=5Q&<&-OCz+)tMe;A;}#)SspbWlc}I-*Fm~Q3p~n9mFgn-1)F=7h8#~1y*pN- z3&k|0&!o{?DFXQbZvKi!?a17?eD_Rf2|) z4!O*&rI9}5fJY993>wW0P>IXEbfe1H5;fu}ANk)BIU--rV?Ks-zh~^qmhl#+N$5mM z2&Jf22iO-%M2GDd`~>Amw@^N9HLG(C$x|#IfnskPHbFZeu8&G`J(Jeg0*DNWFa*lY zqfwgtPTo7vCvJj1ir=|_g0&4}Bh1K-pp=yR((zbSS5jy=lD4yFVqJQd=y>jT+r0zM zYlp9Y70MPh_vSz}@>2+LjmQ0hGuUxi*w+n#z2733LFww?C^jbB(vmM-ovtzJ zfx1-$Yp%V#BFqjxYqubelb*RAzPjd(K&kB&B`JQIYEh~a19c14#-2qYx`o;4`~M~m z|BCqg>|i2YJXx@sK#jP4Wv9_q7~14Xo_4p7{g8@jJdF-E|NA*xvtyS52qX8HEGE~& zKLLMWf69GIG`5crV^)RP5Aa^s3!AOcGU@1#Q03@Gpu(;;?_aG+H9Ma34=e94xrP1g zJtk%L-4QkC!1LH&Q1~bUV~MGTiYY$m4VIA1f7 z4E-Xs_Avh@(avh62W97MyC&EEjz zv>%+V7TlUCHYe4-^lkIn_0|Och{4n9DD;Y_^{n4(_)~F2Ua*);)jri8k^Jsj{oic8 zGqK`f!Nq2VV}oD_K!OgH%npb#l=jeB<)K1m1uRwKXbcTT=Fg!VOT8mS#lEHuh%F|E zarE#hrkp(&r7^$e>HD8WbW_=&6hqyi4@%zt3M)@QayI8{tdtOPaY&fBGH|qgh}n#I z&+ATmOeK}fiza%kIr8_tAUfEPw5i6HcUtJI8Yh2+e`ioD(g|$T;SDn#0~8NZvkEi( ziL2&>Z)@@?t{Egme<|o+L2>EfRm#B_#d*xR!wRUCcONV;!KgW#nH=bVF~p z8s!5kJkbf}uEi5{nZ9gRRSsYm5Io^xdV|_&*~EOc4Q}-B%AxHt7Q0%mEI`D2RWVH;d8HLWHWFxO*AkTz>3gcRujxzBK z;E{5UU7g@gw<5a!<&Er4pd#4tZ%{1NvmO$b_TZa2;_I6q+P&O#Pn@9&QHgq$!iUQG z`d2CWz!4YXc>cEGMbm7n1eZU6&-W~FLe8=oEC5|^YG;9^g$u=~AsH!CkY(Wt)4K50 z$D3p5FEy6~V8!1?8=>0XR_!yM|22qViwo@cDz=Cb3)_W}AFg^lxsmQjx(L@=)$d;* zJF7Q)t+o5tX9vBg*YanlR%_xU@^Hq_*6k<2l_`aDe!s3NyQ8Q@V$g0v$lD83-8>u=C=G}p=tq;8$z%7b>Vky_zhlaHTMUXyvgD6m4f#bd_# z1!=tVma^+{p@_a(PL$n#o@r(x@)mVf`sg^;eMkc+ljM$&Bm&k@DlzWHTE{NVAL1qM z&E(f;H)&)kf&Onnf(P)CRGk&`Od%J#)in^IAZ!>{pHb6->~%ST2Uuh%e+4z+(|NlW zd++|7M;&LK1(EsaBx^c$T5gwi7NC0@?!Uo7{I_i&MN!es3YA9e`s8j>&?e;&#21lLXL5Uuvf52E32IVv`1*Hn z0*fAj4uI~&v%ryiHZ7YO+O3Q(BxyaMnme+8SV~zJmu(R;*L_Y_VM?XUG&*A^SYc*% zgk;S%g?-D_6Q-hYKKzq$H2}M_p3ZIH7`@Km-n6i)- z$xlc}W{$S%B5Fp&JV+QK;hx7eNCWGK1G<6E{bg~#d=epTT&hoo^zs*f1PkmE4DEn& z7PFaO#pdv#Zg>5&Y)4!$vyzwq6f-fPG#_iK)WQ3GHcL4RFR@~=>Mto*rsOVe2=`h7 zQqj1V(_#Af=4m$!mzG>-G>jz%^Hu$ObuKlL0M-k38qVk1jmd-^`QhyOnR*UAPRa5| zH5m_m`@u?XyT+}iz?Hdy(>#0Pvh5(Hd8)J1?ssGWeX8)Q4&@t_W0Nu__cM(NN)y~; zX7ju~$K@=Yt2$-}JPhYkibIALFtB*jIg}hN_ufLkLM;KuAAbFh?hcyG(H;RAJSMbl z9 zHK5OfVgf1$2?oNj@SG+OiHVV7!rVBKxg02iBX#43HE!u%4w3lWnxx-4>;y`3>8b$3 zH0OW-`r&VQabqPXOn_M($2Pl%KpN{6%0hSp6_|e8=A70`xkk|IQ)HdQq3!Aem@%?JO?G8bX1q~09m`1Ffqdh4_j90n8Mzy9Yk2)xR1mdRuZ>D!g8~bPflc54uNOhL}eBIjP zuOMo`gIZFZ!-8va+xWqtt&fs$`!W(R&bde|3?@pEmlZ4664R2Jh2BNR#}YGq5Q1?Z`qV^`z$nZ4?}vw}EJ*>T=vYUX7ICKL7(cuOq^&UH z(nj<<#4+>BU@i|josfB1Gn!0 z3$E(rm+=P=jN6H5>ZHM_2G=yjUB+v>fMausbf!7*FpXj7Hvxpv(sbYTl3sMTAi(M0(TMJj504%!?Z(1SqXy12C zli8S8-f}9hV3T^$bT=a$U5W*=8CL)C<}O2@s+vwyIg5ZSLYZLL{rGJ<;oW!c!-4^z z>6dWKg{{yzQfA1Mi|j#RMZN}c=DUBf8Y{)rJ5zCIda>rf}Czv zFFoRMcjI1mMOFObSmz5T2-4|a?PkCZR5;4G!~Y60xra)z{Q25g!6>L~Y=H>f=iqk{ zcFw4!|2BLkNZ&)X?lkCt(4TPvS{68jKYESX+?StFR~9(Znt{<_n+@2UEyXmbIGjWM=L0nUfl=jx(8R(Id%^v;qCCyAcmeCFG&IH~b71ui zKDiB`&Wwl;VG`y)xmOFBkO*-)4X9co2YY`?0|ge|l95A`(IK zXY}AsJ}jN#N&2q!2rn_TIFGukfWtVK1;)bP7n;4`pT(@T9f6>29%BN6kvj{xF>J^I z%GOHfgXn;|ze1NM(mZa2u{$dbn@Yt3xm2H@BWWe|G~DUf&w2-I3UAR$Z<5m7S;YbX2^3*7E;cZwlx_85AFy zfSY<=L+>3&Cv?n7NM<_Y=4ZMY#l0p=fy^zM;86iyRXz z6eoCSI=Lrs^8MUquUj3fk$rO{^~Sh^yJzEb_Tj!?3{_uwm~4Ji{a(^kSfU5*rMM!1 zc3EG%Q`KbXF-{O|1fZP7D&yfn+8#LjC1uRBC$?0%bb{vAw6Xp@z?G`^=e@izagA@6 zM^=vQMIzmXHPK}*s2Rv)p$XuaOE%2@f6R*+zi$hkj4jAnhXiAz-rZ{=pqFOM4*Qsz z8meOxdqV!-tcH?Bc^g4~F8hah)*(F`Kon>fD zwQ#nFbrkkg^tiT#Mn(O zUeUx-zwm#X(>G49Rd!KqESJsS)D*QPnBZYx6-loA0*kVZTd`|wlH-zfYEz)38NEUG z4&WJ_r*g|9bCjg8iw0=6CNVs19uI;e?!$Ld#dSSLHJiKR;$b9*5YM%u=o46tyz)xq zZ`7Y&EaAf?j#xZuw!m9sDQq51P<;I@D!-(LMJF07^4hs0@R6}JDwVmGfU^m8 zi>nAuwkIR__M;~9N+fI{uSuSA-NSzBN*RRyaQ%RRhdH4NA9kW1o#wJlV)4*p!%RIb zN=t!*UU#CjpZugb(aPRx{iIG@9>DI}c@3%Q>8ea zVjTD188iVx*nTnYi_$9>qncueO$?5Peh$zpo>;}pC5+t6q5L<4Tx7k6@J$HKzMJ>* zDn&!Y{mxc7#Bseb3V^B>*H?2I-0;B&a=sY!q>+xNMM+kc)29XrDi5;;Ty0Wo#vVUx zlb^%HLff}Hk}KeH6xHoa&9$y~HzOJlvk5MR9JH}jjSiE?6y=6lG*$cc$cgktuTXY` z$U%`$L{y+Lq8>W3n>}~lH;d_@`2mFQJYk{?8xU%Y zh1tM8J#5VPRcPANS&3c%Myy13L!G8q#_%W_QLil}S{gqr`hBL-JR#9cp?HIDML_FV zsx~dNZLG8-GG|SJx8Z1NPlQbF%I{VIycfYM{8zVn)H21mmU4&nqh(^uIh)jd6&O<&nao>)c2iIWJ%W=07wi2#1|R#Uqb;bR$mwAbU69$WjjbjzMzaEudZQm4{6=0miP9~?tkwx!}^~fJyh#1Rok2D48KNPCQYZ8 z$8LHnKtc>#2XMyVuYRh@ELYSSw>YqdKWD3jlctZu=w8&Si#-=7^Iif@t`cgK8c`Lv zAKJ3J_q#DCqvSvddI18J8KMlk&zyyB3TmP*(qVgpBxKSC5MZnW-v_UF9W{0&5Gl|F zI6AqxD7lp`-DJh0w6{4MYr3?stl?APPTC!#IJB+Y|c55oL z9ll@#m?Jtwa;3RBMz}LU`AXn3yf+XxSwW2@zc*p$eedt{zg2;E9y#(YY)lOKV)Gd6 zNV@MSe3K-8ouR`QEZe`v8zG7zc{K}>nz^l0`iL^`AGvR>q5EoeyUeYIGEF1V2_j0W zX6un6=E0wZFjohns^DvH*mc~aM(G`5dyJl-PtV%>D8yozA#=iU*4>``IX5gD;#L>L z=IxAqGUaf4X7u;Pm5xeS9XgStEDs|<(MdU~jX0VR?vf-S2VHck=*0Qyx=`aT&siz9 zz#IEhgNA*k_wHl>-%Y?=@sbo#MS*0_gxUljNQjMyGErISSko5SYfmE-GGzsOR!DUJ zc-X&47XpZK3K~Czu1Jg4q}%3N#AfN!%56R{x;fq@xHGtDBIZ%s2ST~-9E=rr7V>Np zEkvD$;8KMfzYd!kB9OPU&||WJx2&z0z$meM6D>DLpEuM0^aRu;nc#P%2SvBVr6rWJ z2nmlY;uO5&pu#2!UTY8UNeTV^YHOev+jJq;LtpI0^&q+0Y`d5hXZQB2fYSpHTKC#( z%^|qlnWOxn5_%5?NeZEM)ItFHReM#?N)rBij>C&MD+~*tX)u z^b`pYF+(J{2j#y7jho}>(hcX3zyeo;Q0%Df6(iyaGR$Fuh7=R)?_90x{mme(KMyv- z4}zKMKXMAXt$QB_0w3!%;VqGgjFFLy8><+3cORk2TI1mlCH}I8*mN^box69KI38q& zat@9|<|6;yk}uJ%YN=L{F^R*a-1~Z6_aWK%pw1l&J*WUt#mAMMbv_5|vhWqV5#)hpU+~lFP z7g(ki@A}_X2W=i#wAU}l8`#=Iwg%tLCDQBYMhPitqKU=#+yGT6xL|z{vXDPYNSL#` zCBIR?M388Ivgbv!7X4aO?V zhM-Mm#_Ueh*7f~88+RgKv3?|TZ!W#Q%KAs9pjZ2TtA}f8QxcQ((rbCabLr1XV6ksW z)OT#oSnqmJ0$yf#Li~_4d&6(=B&_uG;f+}awa<`zI)VbL%xq-s{aesZZXP5S@NfT} zvS^fW?=6>HW4o^LWq`H=smTrcH4farf=K)&^&YzrS#i}Hz&xHG)i=}of4KkKq@{YF z^D=Q9?3WJ9n<FW5xgotC}uXhU)VqN{Y6 ze-OD;*X2D)e64JVSL%9Qj?Jv%AHUa7Ly;82C7Lx!0>r4CBuL^VE`X@F_I5~530`NV z!=N7k)Fh#yRm( zs+XTs?A`(DD@~^X$DaRlXTl?qKb9PDho@XU+8RhW+H}Z}c;EdSbomd~EY90Hvk3r_ zUtTr}r9Zn52x@}IrU9~2aAVXRJ&a8N@3`S~kpP6jp@^4=mhO!=v~75=+=Igiq6yl( zIi(sF04F8RIIAaH#pKlrAGknTFELf>(n^zaq!6Gex|V_UCWFgJS(%~LZM5g-PU=X( zu~FGV7P3|fts5B^6jwErd#j)uq?%F=qH)-N4C3cP;{f+HBaw&bbZElgD0y4cfOxr*F{HS4Q?BW%> z`zr|YDU{IboxKOmG6geG)1WT)29EckBjVJnuz+s>F6U8@Kye?huW(ef#Buv_FdUXk z1jl|Nx*U=%G--lMj7vVw&6?-tg#X+c;_`y&Pyz+J)b-|0O9G{xz5)Vhb(16 zr#Zh5!wO{Is7F;l$#&5X75Lfwhc7@-;_@)lakV`fe()Ih7rgvrSKRObp_CCRB=oDK zT7c3u$W1WC#d=aiPv-@!dH=qV)q3l0XZ?m{ZMxUm?Pn{t5)>1qcSqXV7=77>xgv9m z+1L3jYHQT^ZNTw7Rd{CeCOAFU-5;^j+v ze#|>b=!GW99~s;Qd=r@_ZxZ1Ea;6YK#k@o}OS0QIv$#GfiCD@IJiashy|d$;M8doT zF%V?vSoR;MfxK9`!bBs@ER{3v=43bj7Q`@{ zJVTGV>SynhE)l(meqZu2yTbeY^mN!h#V}u(^M6$h?=JM}5g7YUU8kF|EXe0-0B>>p zAq>6HqXu7$5Uu;0I7L*2xalWQFKa@3D6V9}9)!|sgZt;9?n%E0zSZ1RVv2)mf zYgS?4awMz3E+=FI###O+JgT?j9=Ut-+t73q?H00ZDiavgAjuAnp3lGd)4B?8;R9>f zsjo2Mn|);7Qpm(NK59xW8)QhN3=ZUa&yaw7pR0sN#$FEDhWi6V8 zsl9jPf7))KLk|8P>B$XM@!Fa8+5~)MadQ@~S zx=7WHVyq?hi^!;+6Y02^a+-5tuGweE@x#ieF;`6%4SAvA8yd!X8odwHzb(QD?}O!@ zq{-}C7b$AB{Z@gBou*wM{Z2rv8DuH~JiZp%3U#vCC~OL@AAG5IAA6@HnQT=O=u^+H zNL0wRo;kZ}>btC=Apq!v*zjnE9T=$oM{R!2C~whO(8`_g+XE3V7Vp?vof8Ym1D3$D z*`K{h*og9P24yFD>>Tn#t@>TSP$JiButzKT*dESEmwMVd$_!u<0~c5)KLTCb#o(Cd zE~1Kt0pW^YBV<}c1OD!wNm_J923s>TVH$xNFN_?wQeNi{**kswvUW*WQkbYzPdecq zRQsAWJ616`7B$CdN!!bhtN=9tZ&Qc!mZ@r@YfKb68LgHZdoied82QcYj?cLs?nT&a z>b%|jV*Cj3%dP{*IezliRuPZBx5ooq#Tc*xRfq1@a*y@9xKaf#yOUzIf0y6Uf0~9> za)hF)nybzyUa4dP<%6TmrVK@cD3?b&sMG9m76dPWTdcj~^O*5DJpw(+4u+OFv+2k0 zXu)-JbgQ#!G8@bRyY>kqHM;_~H_>?^^EUa(AQ$0;cKx6XzWMf7djT)Z8U8e(K9>wcXlnn?Q14_ZosodSkjrU7T2^3HAI;THUB16vWe9Jq>EU~MNGGBp% zEy1L3vC9<6%id;4;~%UPBKx;MI}n0P4eVse@;r<=n-T z%>QvGowk5P*aazh9gZYbRZ*ds?t*SaM%MLEkUAv@y$gCb_g7HSHogQ->uP)vjK5)i z^T*f~8+T;rNc_O|aBN@lW@K8B+>F)%-x2_BXpO4cC@=s&MSm*gj?bQY^_beKUrloGI%WKwmU{Q!k&Q-q9O&6 z7*}l0jH>BxWu*&Qb9~$7PS$26o5Mc{2w$xX@nd%@_C$tGAiUiZ8bbJ7kG$i%TUb2~ z$%V|(K85~dBo7-rCcT}46NL60$~_uIc5MzfV02q5{m!GH)^QkrQ)*^luRY%C>sf8= zx>SkO_G)6iicH5g&r~ySNsCDxGqapc>ngkJu=rhQ&lO zEr)s=AdE5xm|F5TVhspEJ1znwU0D~~`U0kh5&*@RbB^$bwah7u77wvrIsjEP2de)= z?Z=USFn&1|0Q^q>$*OAKF9;25HXnFnPutfoUKHa{WQffmVlBl&i+ZNt3}YKYjNXgs z2LOYXvM3L&{q<7RwoQZY`av0&F!l-U5$JFyefb{mc<}jL!A9GvpKlN^-M%VYiG;0x z)z*lfa8?GW0j#Cp+X~7%Ya6vxxO$#l{YV0m|1$CaZ3F%*;_vg>qFtekh@P^2F~jPU zMn>@Np=}Ed+OOdB>Ln;?&ienlTm|!<1dhfI*u(5m2pb`^u}&y;6x#!u4uV-8f;KsK zkY{=@KM9TO9YFT(!Q?a8rB3)Z;gIa1JGpvX(l8wC#pWOs_vfDk--I3=}kZf3n zC4Z@$a*!lcicQQXB6C_|&9@#$W<2f}>I!_`{K*_l+X+G3Fl44OPpl`DVZiAcS2OVa zZ^}m+>lbbt^-qF8e36EAXNiBeurn(RcHWLxGCd$O~BKsA95u@XLnGlVzr^+=w5c=3wT zo#~*(iyK33pxLxg>hm4Csp+9LfNj2!~f zq}s8hnw9oOqzVcmU?P?6`GNs~a+4O++H;2v)Le&QY+ zv4ycxss34tDgCEt3|0#jmr{j3Pg-ZfJU}bxq&Cm14W^UsI2{N_OX;=WHtJ|ydwpIX z)=*y7|6Vvp{s`1j`%Q-XwGN(^jPu~W3!iK&RMAyu}f7BR0%1&@W(Oa28Do+Q0h(poS13cq*}0U z0?36{T6>7_7#v+aOj&AmeEP&wA%{=;E4^qgzuB#R@ z%l*=#CeYtwVhsxCcms4i1f)r`88w<_pqThA#yzJ5m0=k|11{U^MiN8S2UL`N{Fhir zx%zcoT^pSMtKTNX0yUzxG$d4<$j&Ua;0&*&!XTKiR50v9vHbx0jN#BWY~Qws27%RC z4b03S-keMHodN=SLut#E&W4~&^J;WPv_D0g5n_LBI(H#WED`_#Ra=?*zfaPdONZu% zmV45oZtcj>n>tc!I!xJ${yzC&3!%>FJ?%z+1xcwL-Pc?nt@QUz9&Ip$V5XEt&d|KZ z{b)W9EUxJfsnu%~(`z>e7-S|tW5}(C=p+!CJ?o;gKD5}ta3lL9T#^Jy&o03Mn`(xY zE`vSL7rK}jIE9>vHI6LMcF;sr^P)AG;{+3WWhDWYrEleeT@yJz0w`BL)}d>_%Afds zjo!ywm#O=&&>J#{qz5`(SI;NV0Ob%dFcTjhL32d-xJ_^s>${W~BZO*?pP5yhD}ERM z{uzLfAh(W%SLSg_!}oR6pw(!Hvm@!c|Iv3q7xM$wM{UB!AtQV~A!f!wrdJI3?jcnm zDX*>>Hc#ouAxuStSSebcVT+G*PNt+3sFYMghhRjYI`aa|JVlwiC@lqIW{%|1iayOS zxyH&N2?f3MIA<@&$E+r%hs+|@S*#Fq8T-YxQD8AHLK9z|nRW7Z45$vdB`h=8ICQ?R zXI9X7g*U0liao75pOS*QgI6L?dt^Z?`AX-aWDi zRq?GBT?%<1PZ?~#76F^O(vxN7q&NU0ZkaRIr1g6~tewebO!eu(u~{&wb2*|ay3N;h z?t)5E@*t9ImSb=)MFu6ETMkO^i1^=v7O|v&Oo-?O?x?N#3$tMdZ`8w(Rt>KMY8~}a zox*`+{|f4W4Efc$ck0j`&BC*Z&BAn>*hWVeN=EeDmRH=rlHc>^^opmId3y6CkD0Ea zt0kx+@K2QuKB{L-PD(LBRQ2_!2R_jguqjPR33*OXjCd?1~_Ea!5@B&d=69|ZEH>=Reane#(^~?=uyh`@_OsbmcNI3e@z+l z=fx}KeZiIot}Fw+Z`lnaV?GwQh6zZy<3W8RiY1M7Bl4G`2dhJyMf9Jdpb*s29{HUA z@hfIUog#;uPnvR;$tF&H4K%~4kFo)>PM7d*z74w~W}5L=5F7ZKis7H?<94Mn^n^x# z5eCjOC4P4-YJt$lb9#bI+{LrZ^)+)G9HituMZS+xdzW&5D<5G$%vK%$@fAbS&h!0& zeX68f%HJ3^(EwxL@IZCQIavo-9Y5{!kQkywv(6?VpJxL`$UWq<87RMmjr`(Y{4dhg zC^zS7XK9a?MYIe};O*5lRIRdZG(VQc*pHle9hewU10aAc$f%J#B=3wPTNvfx&LrXM z)A4#%o`@oR8l|8%xC>ER-B@P^a`#&9!k7rpbm(Tg?)n*L5Z43{FKjhuu=^TgfT4HCeF{@=5ljc)R*Ak$!17ooD|GtQj5LP%E1*IFC@W>88+aT zkJ66A!y(m<6`B=4?n1lwnC*jB{$ShI@{jf|y?WZoMH1qwrMZxyMzksp*U|7AYZmh_ ztjZMQEPcsKU?92pOC><_YfJIaf26kNo5q{!sD|#{&`V8~dD41WX9B>y45X8MS=>Gh z?BsRFf|apqP6i%<(I5gaTmQ+bBEiE{2ukkQjgokpb`+nNPYZb}08Rk>T zyD&6)#hI3)bzXRTjlKdVAV0Fr25li_l$1f+$^CZ*DGuQ)5!vWgK|8;_=U?%XLa7w< zm|@VL9J9r6BdJ*aUu9M1i@RIdQ1g1hu2Yd5Q~UjWW1*YCNfRcS1&U}qnBoMXp3>aI z_=XUUe~Er%7c*VUO}l^9uRw8}*fgQvtU;JFe$QFBAi>?Xy)=0=O|?d)Wa49f!T+fa zI`;0^4wBCd#M`SeTmw8qN2rM5ze-rj+HA1a5=k)~sJ^9qW3M=Xh0BvA?d0iGh`R+iuUd1 zW?c}<{f<$ACjn2#_O73JhBd5Z_Pi+pnLPNRcmon+d&sn3jvoVa#-93{R6~sqMX`zV z1;`1ENSqFN6*)TH-8Ek+$bh*0%$T^_j?g2%&v%j>!i z%ZjXQrJ<~qtYe7^q@=I=btl7^Xmv+Sr9I1v*m0@pI+_^u?z}*8q;qa!C75`NoKa3_ zTCTlYg9Q$hOfr1&rT2{g`%{#g$e&@kW>v+o-Mrq*bw>|Y(mnU~7S9L;bW0(D3B8;6 z8Tqn-C$bWlhJR#P2hPT~E@BRTi&uD`=qqx~+EO>CgaF3LBcaCfo@uHnL}?&{VJiHBX0j@(7nv8#%ro} z?gTZvYP>*$PR?ti+47PIbwn-ZnmiVm<=FE@5Irr$JQG6WB}#qgjZJSU``ZOD#N#Ih z1+zQxRaQjriCaNeQFV#WBvM@J1s+&4MVhDDX4~6%%_E`u6qE}!zcn3ivJo=GG^&e0 z*(B+`)aEuXA4fQZtA6F(fD1STpM$7Qn$}_cAbw^gj})$k^VC-*I$a~P045VHfw@!j z^oM1mC?dSw5&m2@sw3N6;+L78$Z+;z`n0lW#0cORR3VecOq-Lcl4`aztQ%o|@b~a~ z|0H&G`>=f3BUw@78>Xv$O0+oXRTB0C4j=2j;C24wZYspvtUnH}f?DFA(rl8WHrO)) z7j(<>k9z!=wyEK91FW7fXk-|bxJtDJW}FcW-Y?>lmOS;rN{1Gepc&)~Hs9&qy;ydb z+{t1U=#}GsnDe4O&w)tcR(ykeA|=+707I@+Fx^HY`3)u_q5N#u4d8OrR0Tg1(IQ1Y z7wx69z9vCB%x&_$K+n9fWg60@w0QNI<^4bD>`4-Kua)rh`hVDl znu~Rmt@{O-oPZ;#XFHIEgYeS88j(u*RbIGuym~hj<2F`$GL$e(J(bI|cS|hLly>TD zoOEarCK9YY%fd*~~0|4BaKk5Fvm!GY`_AP1)B9I?rYGESjP%rTM+vLJhq zBd*o}yUNdz07bD^kmM}Y22a*{FH9w7?_5m17czzR7G_8C^IgI$Kz^1scNS)>PXp z%n>h2T5`ZXRv4=l=>7rCc~8iZToSZWVipgSjrJaucD0>=PUMlKqUoI7JLWgVrT$j4 znh8JGab5K_%0`)so279QD#B;OHBtlxIG$A=t91wAlo`OMqVEHu?>@Wend&3r8V+Ql z8@e4W44|&Zruh}!pd{ZP4toQvlE&4NTuqc&R;=ik&OUvch=p2RI%O5U8Z)iG4CZ}f zUa@Aic;f26D9m@fw!#VjL~~K3J-Tksfj^>279z(LlA`lXWJns$(~KXgX-+O1$X@}G z3Qnoah}~#=?V=L8f5br(UK;J(WXpCv8p7u&08%Z@cs(2 z<#FgX9E&{7e(&EA0e%G_%EaA!RsVw5m=)f0bwJ1z+cR_~=(jY^_i|(I%2Ah$cas6u z1Rh`fL77l9~Ip$O(`nK7`{*o6bYmZ z1Xs}hdtYz0n9`~=86iis!L&4RP9$>}a3vzu366;2;*{;(;mPehAva}wqeKtvt8Px$ zm~OCDA|{3kw2JM%(uz7roMkU#d_{!a>-Ud1?aEs_34yam-$=#wCDl$KU#-=Ihg)B~ z_`KW;`%^`l5_J(YMd2@|S# ziL99QiPw6k$b^roxw1{ww>*SIsqIL4*G&HP&g&y#lP252K-$r-_F;ug&WS-$-$ya- zUk9jfDgCk?1hltgbMiLw9xt*w(pF}HJpGE-hC3zMU-v;MZial3q3idN_;7)_n!&_p z3ctKi>YAM*)-|=8#b&6T?C@&SAJ__RnaPqGXxAY$@Y_uay<)dG#}f|rv~_#BmqjzO zXlK%A&(~fs)udD|H9L&iPfJ6@PC|V!C*10JF|<`asurs&*k?pM zSDZ)r0Zg~QcYz&+D;R<^+zO#&oqf6(zYDkT=2%yA#)LId??o`*@MX?2^lw1}?7Sz` z=!#Df0Rx4I|F5(2j_30G|38xLZIdLcNZFClKv^X_WQ52b5i;u~+1bg=9--`+QMQng znXJgns_gmgpJ#rz_xtwxU0$ER?*BZla~{`uU9anUo^zh(9I(uAH%0ATxWzIMRCk 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 dFr7!jboDOM*g1Mj} From 551b0dab760abcd2ed76afdfcaa3e1facc165e08 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 10 Apr 2023 19:11:03 -0400 Subject: [PATCH 14/39] chore: prefer crypto/rand over math/rand --- share/test_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/test_helpers.go b/share/test_helpers.go index 56fd9367b4..c02bfc55ac 100644 --- a/share/test_helpers.go +++ b/share/test_helpers.go @@ -55,7 +55,7 @@ func RandShares(t require.TestingT, total int) []Share { for i := range shares { share := make([]byte, Size) copy(share[:NamespaceSize], namespace.RandomNamespace().Bytes()) - _, err := mrand.Read(share[NamespaceSize:]) + _, err := rand.Read(share[NamespaceSize:]) require.NoError(t, err) shares[i] = share } From f3b5d9f975383b778bcf8e2638aa2b7ea61ee976 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Thu, 13 Apr 2023 12:27:19 -0400 Subject: [PATCH 15/39] chore: upgrade to celestia-app v0.14.0-rc2 --- go.mod | 3 +-- go.sum | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 42bee4dd2e..4fa44a1c68 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/benbjohnson/clock v1.3.0 - github.com/celestiaorg/celestia-app v0.14.0-rc0 + github.com/celestiaorg/celestia-app v0.14.0-rc2 github.com/celestiaorg/go-header v0.2.3 github.com/celestiaorg/go-libp2p-messenger v0.2.0 github.com/celestiaorg/nmt v0.15.0 @@ -329,7 +329,6 @@ require ( ) replace ( - github.com/celestiaorg/celestia-app => ../celestia-app github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11 github.com/filecoin-project/dagstore => github.com/celestiaorg/dagstore v0.0.0-20230404123415-177451f83136 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 diff --git a/go.sum b/go.sum index b27fbb6c74..a3e4e3c512 100644 --- a/go.sum +++ b/go.sum @@ -201,6 +201,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/celestiaorg/celestia-app v0.14.0-rc2 h1:a/hY7ObIl5UFgvH6idYh40KF1o/Ant8G2HdTa3CsumY= +github.com/celestiaorg/celestia-app v0.14.0-rc2/go.mod h1:GUQDUi/0nhOJLAsP/i2RHnw+U/nN059OzkG6GeQLjhA= github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27 h1:7EIZ0pzRB4eaRnsscTLtLruJhokmcinHUgB8ruDh6sU= github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27/go.mod h1:gMRZPCntAn3FvoF9/NBszOolf89Ggrj7qLbeFIUFam4= github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11 h1:4pHUj2JP27fEJ1daxlJNGi/jkCiAiRx78sAftzpCbGg= From 0a9c80ca6f4bb9e20accf830e192e989ff562ff0 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Thu, 13 Apr 2023 17:41:32 -0400 Subject: [PATCH 16/39] fix comment --- share/getters/getter_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/share/getters/getter_test.go b/share/getters/getter_test.go index 037869cfe0..4e4cfc2250 100644 --- a/share/getters/getter_test.go +++ b/share/getters/getter_test.go @@ -140,11 +140,12 @@ func randomEDSWithDoubledNamespace(t *testing.T, size int) (*rsmt2d.ExtendedData idx1 := (n - 1) / 2 idx2 := n / 2 - // Make it so that the two shares have a common namespace. For example if - // size=4, the original data square looks like this: - // _ D D _ - // _ _ _ _ + // Make it so that the two shares in two different rows have a common + // namespace. For example if size=4, the original data square looks like + // this: // _ _ _ _ + // _ _ _ D + // D _ _ _ // _ _ _ _ // where the D shares have a common namespace. copy(randShares[idx2][:share.NamespaceSize], randShares[idx1][:share.NamespaceSize]) From f934f9e77710c60ed1bb362a47e6ec0a17f0c77f Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 11:16:07 -0400 Subject: [PATCH 17/39] fix: lint --- api/gateway/share_test.go | 25 ++++++++++++++++++------- share/ipld/nmt.go | 1 - 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index bebf0ee7d7..88eaac279e 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -18,7 +18,8 @@ func Test_dataFromShares(t *testing.T) { } smallTxInput := padShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace 0x1, // info byte 0x0, 0x0, 0x0, 0x2, // 1 byte (unit) + 1 byte (unit length) = 2 bytes sequence length 0x0, 0x0, 0x0, 0x2a, // reserved bytes @@ -29,14 +30,16 @@ func Test_dataFromShares(t *testing.T) { largeTxInput := [][]byte{ fillShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace 0x1, // info byte 0x0, 0x0, 0x2, 0x2, // 512 (unit) + 2 (unit length) = 514 sequence length 0x0, 0x0, 0x0, 0x2a, // reserved bytes 128, 4, // unit length of transaction is 512 }, 0xc), // data of transaction padShare(append([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace 0x0, // info byte 0x0, 0x0, 0x0, 0x0, // reserved bytes }, bytes.Repeat([]byte{0xc}, 44)..., // continuation data of transaction @@ -47,14 +50,16 @@ func Test_dataFromShares(t *testing.T) { largePfbTxInput := [][]byte{ fillShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace 0x1, // info byte 0x0, 0x0, 0x2, 0x2, // 512 (unit) + 2 (unit length) = 514 sequence length 0x0, 0x0, 0x0, 0x2a, // reserved bytes 128, 4, // unit length of transaction is 512 }, 0xc), // data of transaction padShare(append([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace 0x0, // info byte 0x0, 0x0, 0x0, 0x0, // reserved bytes }, bytes.Repeat([]byte{0xc}, 44)..., // continuation data of transaction @@ -73,8 +78,14 @@ func Test_dataFromShares(t *testing.T) { { name: "returns an error when shares contain two different namespaces", input: [][]byte{ - {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, - {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, + { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + }, + { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + }, }, want: nil, wantErr: true, diff --git a/share/ipld/nmt.go b/share/ipld/nmt.go index 020c7112a9..e881aa289b 100644 --- a/share/ipld/nmt.go +++ b/share/ipld/nmt.go @@ -36,7 +36,6 @@ const ( // sha256NamespaceFlagged is the multihash code used to hash blocks // that contain an NMT node (inner and leaf nodes). - // Question: does the 8 in this constant refer to the size of the namespace? If so, it needs to be updated. sha256NamespaceFlagged = 0x7701 // MaxSquareSize is currently the maximum size supported for unerasured data in From 23a611dfa6bef1b830eeaeff19aea2160fe48b0b Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 16:13:05 -0400 Subject: [PATCH 18/39] fix: TestShrexGetter --- share/getters/shrex_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/share/getters/shrex_test.go b/share/getters/shrex_test.go index b9960c1fac..5cca0de115 100644 --- a/share/getters/shrex_test.go +++ b/share/getters/shrex_test.go @@ -15,8 +15,9 @@ import ( "github.com/stretchr/testify/require" "github.com/celestiaorg/celestia-app/pkg/da" + "github.com/celestiaorg/celestia-app/pkg/namespace" libhead "github.com/celestiaorg/go-header" - "github.com/celestiaorg/nmt/namespace" + nmtnamespace "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" "github.com/celestiaorg/celestia-node/header" @@ -128,10 +129,10 @@ func newStore(t *testing.T) (*eds.Store, error) { return eds.NewStore(tmpDir, ds) } -func generateTestEDS(t *testing.T) (*rsmt2d.ExtendedDataSquare, da.DataAvailabilityHeader, namespace.ID) { +func generateTestEDS(t *testing.T) (*rsmt2d.ExtendedDataSquare, da.DataAvailabilityHeader, nmtnamespace.ID) { eds := share.RandEDS(t, 4) dah := da.NewDataAvailabilityHeader(eds) - randNID := dah.RowsRoots[(len(dah.RowsRoots)-1)/2][:8] + randNID := dah.RowsRoots[(len(dah.RowsRoots)-1)/2][:namespace.NamespaceSize] return eds, dah, randNID } From 0b37134d6b7c907007542d96b9dfc9f232c55d06 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 16:14:13 -0400 Subject: [PATCH 19/39] fix: GetSharesByNamespace --- share/getters/getter_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/getters/getter_test.go b/share/getters/getter_test.go index 413f083d6f..603bf23d88 100644 --- a/share/getters/getter_test.go +++ b/share/getters/getter_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/celestiaorg/celestia-app/pkg/da" + "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/celestia-app/pkg/wrapper" "github.com/celestiaorg/rsmt2d" @@ -212,7 +213,7 @@ func TestIPLDGetter(t *testing.T) { assert.Len(t, shares.Flatten(), 2) // nid not found - nID = make([]byte, 8) + nID = make([]byte, namespace.NamespaceSize) _, err = sg.GetSharesByNamespace(ctx, &dah, nID) require.ErrorIs(t, err, share.ErrNotFound) From d3a6243000b906579450d55a17ca9b7453c995a8 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 16:17:07 -0400 Subject: [PATCH 20/39] fix: TestExchange_RequestND_NotFound --- share/p2p/shrexnd/exchange_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/share/p2p/shrexnd/exchange_test.go b/share/p2p/shrexnd/exchange_test.go index 8542992e0e..e278a892e7 100644 --- a/share/p2p/shrexnd/exchange_test.go +++ b/share/p2p/shrexnd/exchange_test.go @@ -14,7 +14,8 @@ import ( "github.com/stretchr/testify/require" "github.com/celestiaorg/celestia-app/pkg/da" - "github.com/celestiaorg/nmt/namespace" + "github.com/celestiaorg/celestia-app/pkg/namespace" + nmtnamespace "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" "github.com/celestiaorg/celestia-node/share" @@ -34,7 +35,7 @@ func TestExchange_RequestND_NotFound(t *testing.T) { t.Cleanup(cancel) root := share.Root{} - nID := make([]byte, 8) + nID := make([]byte, namespace.NamespaceSize) _, err := client.RequestND(ctx, &root, nID, server.host.ID()) require.ErrorIs(t, err, p2p.ErrNotFound) }) @@ -47,7 +48,7 @@ func TestExchange_RequestND_NotFound(t *testing.T) { dah := da.NewDataAvailabilityHeader(eds) require.NoError(t, edsStore.Put(ctx, dah.Hash(), eds)) - randNID := dah.RowsRoots[(len(dah.RowsRoots)-1)/2][:8] + randNID := dah.RowsRoots[(len(dah.RowsRoots)-1)/2][:namespace.NamespaceSize] _, err := client.RequestND(ctx, &dah, randNID, server.host.ID()) require.ErrorIs(t, err, p2p.ErrNotFound) }) @@ -112,7 +113,7 @@ func (m notFoundGetter) GetEDS(_ context.Context, _ *share.Root, return nil, share.ErrNotFound } -func (m notFoundGetter) GetSharesByNamespace(_ context.Context, _ *share.Root, _ namespace.ID, +func (m notFoundGetter) GetSharesByNamespace(_ context.Context, _ *share.Root, _ nmtnamespace.ID, ) (share.NamespacedShares, error) { return nil, share.ErrNotFound } From 2e1e5ce93f98efd8894488678bc8a2f2e484d679 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 16:19:34 -0400 Subject: [PATCH 21/39] fix: TestStoreGetter --- share/getters/getter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/getters/getter_test.go b/share/getters/getter_test.go index 603bf23d88..154d727931 100644 --- a/share/getters/getter_test.go +++ b/share/getters/getter_test.go @@ -137,7 +137,7 @@ func TestStoreGetter(t *testing.T) { assert.Len(t, shares.Flatten(), 2) // nid not found - nID = make([]byte, 8) + nID = make([]byte, namespace.NamespaceSize) _, err = sg.GetSharesByNamespace(ctx, &dah, nID) require.ErrorIs(t, err, share.ErrNotFound) From 9cee8005397e6a84f7fc2d130c29215c7577dad4 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 16:25:31 -0400 Subject: [PATCH 22/39] fix: TestService_GetSharesByNamespace remove test b/c it seems duplicative of TestService_GetSharesByNamespaceNotFound --- share/availability/light/availability_test.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 8410f389ca..5ed530596f 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -127,18 +127,6 @@ func TestService_GetSharesByNamespace(t *testing.T) { require.NoError(t, err) require.NoError(t, shares.Verify(root, lastNID)) }) - t.Run("no shares are returned when GetSharesByNamespace is invoked with random namespace ID", func(t *testing.T) { - squareSize := 4 - totalShares := squareSize * squareSize - getter, bServ := EmptyGetter() - randShares := share.RandShares(t, totalShares) - root := availability_test.FillBS(t, bServ, randShares) - randomNID := namespace.RandomBlobNamespace() - - shares, err := getter.GetSharesByNamespace(context.Background(), root, randomNID.Bytes()) - require.NoError(t, err) - require.Equal(t, 0, len(shares.Flatten())) - }) } } From c505103994accc5443e4ba0ef5868586b02c71d0 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Fri, 14 Apr 2023 16:43:27 -0400 Subject: [PATCH 23/39] fix: TestRetriever_ByzantineError --- share/eds/retriever_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/eds/retriever_test.go b/share/eds/retriever_test.go index 1c98c133c4..e90216de13 100644 --- a/share/eds/retriever_test.go +++ b/share/eds/retriever_test.go @@ -75,7 +75,7 @@ func TestRetriever_ByzantineError(t *testing.T) { require.NoError(t, err) // corrupt shares so that eds erasure coding does not match - copy(shares[14][8:], shares[15][8:]) + copy(shares[14][share.NamespaceSize:], shares[15][share.NamespaceSize:]) // import corrupted eds batchAdder := ipld.NewNmtNodeAdder(ctx, bserv, ipld.MaxSizeBatchOption(width*2)) From df4d5f1ddcb45fe07346de2318aa0dfe7639709b Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Mon, 17 Apr 2023 10:45:03 -0400 Subject: [PATCH 24/39] chore: address @wondertan feedback --- share/empty.go | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/share/empty.go b/share/empty.go index ea4544f760..3934e9b645 100644 --- a/share/empty.go +++ b/share/empty.go @@ -21,10 +21,7 @@ var ( func init() { // compute empty block EDS and DAH for it - shares, err := emptyDataSquare() - if err != nil { - panic(fmt.Errorf("failed to create empty data square: %w", err)) - } + shares := emptyDataSquare() squareSize := uint64(math.Sqrt(float64(appconsts.DefaultMinSquareSize))) eds, err := da.ExtendShares(squareSize, shares) if err != nil { @@ -54,10 +51,7 @@ func EmptyRoot() *Root { // redundant storing of empty block data so that it is only stored once and returned // upon request for a block with an empty data square. Ref: header/constructors.go#L56 func EnsureEmptySquareExists(ctx context.Context, bServ blockservice.BlockService) (*rsmt2d.ExtendedDataSquare, error) { - shares, err := emptyDataSquare() - if err != nil { - return nil, err - } + shares := emptyDataSquare() return AddShares(ctx, shares, bServ) } @@ -67,10 +61,11 @@ func EmptyExtendedDataSquare() *rsmt2d.ExtendedDataSquare { } // emptyDataSquare returns the minimum size data square filled with tail padding. -func emptyDataSquare() ([][]byte, error) { +func emptyDataSquare() [][]byte { result, err := shares.TailPaddingShares(appconsts.MinShareCount) if err != nil { - return nil, err + panic("failed to create empty data square: " + err.Error()) } - return shares.ToBytes(result), nil + + return shares.ToBytes(result) } From 4f3e0ee99fa11f1b0a49af44cde76b0cbdefb249 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Wed, 3 May 2023 12:45:52 -0400 Subject: [PATCH 25/39] chore: upgrade to celestia-app v0.15.0-rc0 --- api/gateway/share.go | 2 +- core/exchange_test.go | 2 +- core/testing.go | 2 +- core/testing_grpc.go | 2 +- das/coordinator_test.go | 2 +- das/daser_test.go | 4 +-- das/metrics.go | 4 +-- das/worker.go | 6 ++-- go.mod | 20 ++++++------ go.sum | 31 ++++++++++--------- nodebuilder/tests/swamp/config.go | 6 ++-- nodebuilder/tests/swamp/swamp.go | 2 +- nodebuilder/tests/swamp/swamp_tx.go | 2 +- share/availability/cache/availability_test.go | 2 +- share/availability/light/availability.go | 2 +- share/availability/light/availability_test.go | 6 ++-- share/eds/byzantine/bad_encoding.go | 2 +- share/eds/byzantine/bad_encoding_test.go | 2 +- share/eds/byzantine/byzantine.go | 2 +- share/eds/byzantine/share_proof_test.go | 2 +- share/eds/eds_test.go | 2 +- share/eds/retriever.go | 10 +++--- share/eds/retriever_quadrant.go | 2 +- share/eds/store.go | 2 +- share/empty.go | 6 +--- share/getter.go | 2 +- share/getters/ipld.go | 2 +- share/getters/shrex_test.go | 2 +- share/getters/store.go | 2 +- share/getters/utils.go | 6 ++-- share/ipld/nmt.go | 2 +- share/ipld/nmt_test.go | 2 +- share/p2p/shrexnd/exchange_test.go | 2 +- state/integration_test.go | 4 +-- 34 files changed, 74 insertions(+), 75 deletions(-) diff --git a/api/gateway/share.go b/api/gateway/share.go index 2bde5ced4d..dd5a120a0a 100644 --- a/api/gateway/share.go +++ b/api/gateway/share.go @@ -117,7 +117,7 @@ func dataFromShares(input []share.Share) (data [][]byte, err error) { if err != nil { return nil, err } - sequences, err := shares.ParseShares(appShares) + sequences, err := shares.ParseShares(appShares, false) if err != nil { return nil, err } diff --git a/core/exchange_test.go b/core/exchange_test.go index 928d15a9e5..f6302b5742 100644 --- a/core/exchange_test.go +++ b/core/exchange_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/celestiaorg/celestia-app/testutil/testnode" + "github.com/celestiaorg/celestia-app/test/util/testnode" "github.com/celestiaorg/celestia-node/header" "github.com/celestiaorg/celestia-node/share/eds" diff --git a/core/testing.go b/core/testing.go index 8b483b40a2..393ec62c09 100644 --- a/core/testing.go +++ b/core/testing.go @@ -12,7 +12,7 @@ import ( tmrand "github.com/tendermint/tendermint/libs/rand" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "github.com/celestiaorg/celestia-app/testutil/testnode" + "github.com/celestiaorg/celestia-app/test/util/testnode" ) // TestConfig encompasses all the configs required to run test Tendermint + Celestia App tandem. diff --git a/core/testing_grpc.go b/core/testing_grpc.go index 2306b61723..d831bc0724 100644 --- a/core/testing_grpc.go +++ b/core/testing_grpc.go @@ -14,7 +14,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/celestiaorg/celestia-app/testutil/testnode" + "github.com/celestiaorg/celestia-app/test/util/testnode" ) /* diff --git a/das/coordinator_test.go b/das/coordinator_test.go index af57c40ca1..3f010d23e6 100644 --- a/das/coordinator_test.go +++ b/das/coordinator_test.go @@ -382,7 +382,7 @@ func (m *mockSampler) discover(ctx context.Context, newHeight uint64, emit liste emit(ctx, &header.ExtendedHeader{ Commit: &types.Commit{}, RawHeader: header.RawHeader{Height: int64(newHeight)}, - DAH: &header.DataAvailabilityHeader{RowsRoots: make([][]byte, 0)}, + DAH: &header.DataAvailabilityHeader{RowRoots: make([][]byte, 0)}, }) } diff --git a/das/daser_test.go b/das/daser_test.go index 5e201a9b69..665c03f700 100644 --- a/das/daser_test.go +++ b/das/daser_test.go @@ -343,7 +343,7 @@ type benchGetterStub struct { func newBenchGetter() benchGetterStub { return benchGetterStub{header: &header.ExtendedHeader{ - DAH: &header.DataAvailabilityHeader{RowsRoots: make([][]byte, 0)}}} + DAH: &header.DataAvailabilityHeader{RowRoots: make([][]byte, 0)}}} } func (m benchGetterStub) GetByHeight(context.Context, uint64) (*header.ExtendedHeader, error) { @@ -360,7 +360,7 @@ func (m getterStub) GetByHeight(_ context.Context, height uint64) (*header.Exten return &header.ExtendedHeader{ Commit: &types.Commit{}, RawHeader: header.RawHeader{Height: int64(height)}, - DAH: &header.DataAvailabilityHeader{RowsRoots: make([][]byte, 0)}}, nil + DAH: &header.DataAvailabilityHeader{RowRoots: make([][]byte, 0)}}, nil } func (m getterStub) GetRangeByHeight(context.Context, uint64, uint64) ([]*header.ExtendedHeader, error) { diff --git a/das/metrics.go b/das/metrics.go index 0fca084732..3bec83da29 100644 --- a/das/metrics.go +++ b/das/metrics.go @@ -141,12 +141,12 @@ func (m *metrics) observeSample( } m.sampleTime.Record(ctx, sampleTime.Seconds(), attribute.Bool("failed", err != nil), - attribute.Int("header_width", len(h.DAH.RowsRoots)), + attribute.Int("header_width", len(h.DAH.RowRoots)), ) m.sampled.Add(ctx, 1, attribute.Bool("failed", err != nil), - attribute.Int("header_width", len(h.DAH.RowsRoots)), + attribute.Int("header_width", len(h.DAH.RowRoots)), ) atomic.StoreUint64(&m.lastSampledTS, uint64(time.Now().UTC().Unix())) diff --git a/das/worker.go b/das/worker.go index c73ad235f8..22277bbd60 100644 --- a/das/worker.go +++ b/das/worker.go @@ -111,7 +111,7 @@ func (w *worker) sample(ctx context.Context, timeout time.Duration, height uint6 "failed to sample header", "height", h.Height(), "hash", h.Hash(), - "square width", len(h.DAH.RowsRoots), + "square width", len(h.DAH.RowRoots), "data root", h.DAH.String(), "err", err, "finished (s)", time.Since(start), @@ -124,7 +124,7 @@ func (w *worker) sample(ctx context.Context, timeout time.Duration, height uint6 "sampled header", "height", h.Height(), "hash", h.Hash(), - "square width", len(h.DAH.RowsRoots), + "square width", len(h.DAH.RowRoots), "data root", h.DAH.String(), "finished (s)", time.Since(start), ) @@ -165,7 +165,7 @@ func (w *worker) getHeader(ctx context.Context, height uint64) (*header.Extended "got header from header store", "height", h.Height(), "hash", h.Hash(), - "square width", len(h.DAH.RowsRoots), + "square width", len(h.DAH.RowRoots), "data root", h.DAH.String(), "finished (s)", time.Since(start), ) diff --git a/go.mod b/go.mod index caa7927238..30b28b4f34 100644 --- a/go.mod +++ b/go.mod @@ -9,13 +9,13 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/benbjohnson/clock v1.3.0 - github.com/celestiaorg/celestia-app v0.14.0-rc2 + github.com/celestiaorg/celestia-app v0.15.0-rc0 github.com/celestiaorg/go-fraud v0.1.0 github.com/celestiaorg/go-header v0.2.6 github.com/celestiaorg/go-libp2p-messenger v0.2.0 github.com/celestiaorg/nmt v0.15.0 github.com/celestiaorg/rsmt2d v0.8.0 - github.com/cosmos/cosmos-sdk v0.46.7 + github.com/cosmos/cosmos-sdk v0.46.11 github.com/cosmos/cosmos-sdk/api v0.1.0 github.com/cristalhq/jwt v1.2.0 github.com/dgraph-io/badger/v2 v2.2007.4 @@ -61,7 +61,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.2 - github.com/tendermint/tendermint v0.35.4 + github.com/tendermint/tendermint v0.34.24 go.opentelemetry.io/otel v1.13.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.34.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.2 @@ -135,7 +135,7 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect github.com/etclabscore/go-jsonschema-walk v0.0.6 // indirect - github.com/ethereum/go-ethereum v1.11.5 // indirect + github.com/ethereum/go-ethereum v1.11.6 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -159,7 +159,7 @@ require ( github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gopacket v1.1.19 // indirect @@ -186,7 +186,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect - github.com/holiman/uint256 v1.2.0 // indirect + github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/iancoleman/orderedmap v0.1.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect @@ -311,12 +311,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect - golang.org/x/mod v0.8.0 // indirect + golang.org/x/mod v0.9.0 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/oauth2 v0.4.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/term v0.6.0 // indirect - golang.org/x/tools v0.6.0 // indirect + golang.org/x/tools v0.7.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.103.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -331,8 +331,8 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11 + github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.12.0-sdk-v0.46.11 github.com/filecoin-project/dagstore => github.com/celestiaorg/dagstore v0.0.0-20230413141458-735ab09a15d6 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27 + github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.18.0-tm-v0.34.27 ) diff --git a/go.sum b/go.sum index 8d1b0226a0..70277b2208 100644 --- a/go.sum +++ b/go.sum @@ -341,12 +341,12 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/celestiaorg/celestia-app v0.14.0-rc2 h1:a/hY7ObIl5UFgvH6idYh40KF1o/Ant8G2HdTa3CsumY= -github.com/celestiaorg/celestia-app v0.14.0-rc2/go.mod h1:GUQDUi/0nhOJLAsP/i2RHnw+U/nN059OzkG6GeQLjhA= -github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27 h1:7EIZ0pzRB4eaRnsscTLtLruJhokmcinHUgB8ruDh6sU= -github.com/celestiaorg/celestia-core v1.17.0-tm-v0.34.27/go.mod h1:gMRZPCntAn3FvoF9/NBszOolf89Ggrj7qLbeFIUFam4= -github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11 h1:4pHUj2JP27fEJ1daxlJNGi/jkCiAiRx78sAftzpCbGg= -github.com/celestiaorg/cosmos-sdk v1.9.0-sdk-v0.46.11/go.mod h1:O3Pnh/fALx6KV5678ckfemIzvidYbVF5H8ol1rb/3+E= +github.com/celestiaorg/celestia-app v0.15.0-rc0 h1:LcOnih4sZ55iIUCtmIQO1UbD9Bq2R2sLWzRvgvDrAYU= +github.com/celestiaorg/celestia-app v0.15.0-rc0/go.mod h1:HEfzQx+VpvRQdwITISCTGPrbGZzfRCFhW9EzdhOXzoo= +github.com/celestiaorg/celestia-core v1.18.0-tm-v0.34.27 h1:RpwimQk/cc+2PUduPDKSwQJWI0+IpoIzQEiQIT/s1PY= +github.com/celestiaorg/celestia-core v1.18.0-tm-v0.34.27/go.mod h1:8PbX2OIPehldawXWAzNWPxBPnfFtcYtjHecE45b2Beg= +github.com/celestiaorg/cosmos-sdk v1.12.0-sdk-v0.46.11 h1:Y+/dAyu7t0F8+EZz+jU3tyZqG10W8LTCQpnHe8Ejuec= +github.com/celestiaorg/cosmos-sdk v1.12.0-sdk-v0.46.11/go.mod h1:uKEyhG8H8hbjebOEEgtyqghJWpuMyF+u61MK5cis+pk= github.com/celestiaorg/dagstore v0.0.0-20230413141458-735ab09a15d6 h1:/yCwMCoOPcYCiG18u8/1pv5eXF04xczoQO3sR0bKsgM= github.com/celestiaorg/dagstore v0.0.0-20230413141458-735ab09a15d6/go.mod h1:ta/DlqIH10bvhwqJIw51Nq3QU4XVMp6pz3f0Deve9fM= github.com/celestiaorg/go-fraud v0.1.0 h1:v6mZvlmf2J5ELZfPnrtmmOvKbaYIUs/erDWPO8NbZyY= @@ -564,8 +564,8 @@ github.com/etclabscore/go-jsonschema-walk v0.0.6/go.mod h1:VdfDY72AFAiUhy0ZXEaWS github.com/etclabscore/go-openrpc-reflect v0.0.37 h1:IH0e7JqIvR9OhbbFWi/BHIkXrqbR3Zyia3RJ733eT6c= github.com/etclabscore/go-openrpc-reflect v0.0.37/go.mod h1:0404Ky3igAasAOpyj1eESjstTyneBAIk5PgJFbK4s5E= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= -github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= +github.com/ethereum/go-ethereum v1.11.6 h1:2VF8Mf7XiSUfmoNOy3D+ocfl9Qu8baQBrCNbo2CXQ8E= +github.com/ethereum/go-ethereum v1.11.6/go.mod h1:+a8pUj1tOyJ2RinsNQD4326YS+leSoKGiG/uVVb0x6Y= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= @@ -738,8 +738,9 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -914,8 +915,9 @@ github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSV github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= +github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= @@ -2204,8 +2206,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2561,8 +2563,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2838,6 +2840,7 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= diff --git a/nodebuilder/tests/swamp/config.go b/nodebuilder/tests/swamp/config.go index f14243d342..630920609f 100644 --- a/nodebuilder/tests/swamp/config.go +++ b/nodebuilder/tests/swamp/config.go @@ -15,8 +15,8 @@ type Config struct { // 100ms func DefaultConfig() *Config { cfg := core.DefaultTestConfig() - // timeout commits faster than this tend to be flakier - cfg.Tendermint.Consensus.TimeoutCommit = 200 * time.Millisecond + // target height duration lower than this tend to be flakier + cfg.Tendermint.Consensus.TargetHeightDuration = 200 * time.Millisecond return &Config{ cfg, } @@ -31,7 +31,7 @@ func WithBlockTime(t time.Duration) Option { // for empty block c.Tendermint.Consensus.CreateEmptyBlocksInterval = t // for filled block - c.Tendermint.Consensus.TimeoutCommit = t + c.Tendermint.Consensus.TargetHeightDuration = t c.Tendermint.Consensus.SkipTimeoutCommit = false } } diff --git a/nodebuilder/tests/swamp/swamp.go b/nodebuilder/tests/swamp/swamp.go index bbe8f7e395..5942164383 100644 --- a/nodebuilder/tests/swamp/swamp.go +++ b/nodebuilder/tests/swamp/swamp.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/fx" - "github.com/celestiaorg/celestia-app/testutil/testnode" + "github.com/celestiaorg/celestia-app/test/util/testnode" libhead "github.com/celestiaorg/go-header" "github.com/celestiaorg/celestia-node/core" diff --git a/nodebuilder/tests/swamp/swamp_tx.go b/nodebuilder/tests/swamp/swamp_tx.go index 956c8cf7c4..656b2f341d 100644 --- a/nodebuilder/tests/swamp/swamp_tx.go +++ b/nodebuilder/tests/swamp/swamp_tx.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/celestiaorg/celestia-app/testutil/testnode" + "github.com/celestiaorg/celestia-app/test/util/testnode" ) // FillBlocks produces the given amount of contiguous blocks with customizable size. diff --git a/share/availability/cache/availability_test.go b/share/availability/cache/availability_test.go index 47df434c06..03df47f848 100644 --- a/share/availability/cache/availability_test.go +++ b/share/availability/cache/availability_test.go @@ -60,7 +60,7 @@ func TestCacheAvailability(t *testing.T) { } var invalidHeader = da.DataAvailabilityHeader{ - RowsRoots: [][]byte{{1, 2}}, + RowRoots: [][]byte{{1, 2}}, } // TestCacheAvailability_Failed tests to make sure a failed diff --git a/share/availability/light/availability.go b/share/availability/light/availability.go index c947e65e63..192e6b222b 100644 --- a/share/availability/light/availability.go +++ b/share/availability/light/availability.go @@ -38,7 +38,7 @@ func (la *ShareAvailability) SharesAvailable(ctx context.Context, dah *share.Roo "err", err) panic(err) } - samples, err := SampleSquare(len(dah.RowsRoots), DefaultSampleAmount) + samples, err := SampleSquare(len(dah.RowRoots), DefaultSampleAmount) if err != nil { return err } diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 5ed530596f..9d7b3fa265 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -146,7 +146,7 @@ func TestGetShares(t *testing.T) { func TestService_GetSharesByNamespaceNotFound(t *testing.T) { getter, root := GetterWithRandSquare(t, 1) - root.RowsRoots = nil + root.RowRoots = nil _, err := getter.GetSharesByNamespace(context.Background(), root, namespace.RandomNamespace().Bytes()) assert.ErrorIs(t, err, share.ErrNotFound) @@ -165,8 +165,8 @@ func BenchmarkService_GetSharesByNamespace(b *testing.B) { b.Run(strconv.Itoa(tt.amountShares), func(b *testing.B) { t := &testing.T{} getter, root := GetterWithRandSquare(t, tt.amountShares) - randNID := root.RowsRoots[(len(root.RowsRoots)-1)/2][:8] - root.RowsRoots[(len(root.RowsRoots) / 2)] = root.RowsRoots[(len(root.RowsRoots)-1)/2] + randNID := root.RowRoots[(len(root.RowRoots)-1)/2][:8] + root.RowRoots[(len(root.RowRoots) / 2)] = root.RowRoots[(len(root.RowRoots)-1)/2] b.ResetTimer() for i := 0; i < b.N; i++ { _, err := getter.GetSharesByNamespace(context.Background(), root, randNID) diff --git a/share/eds/byzantine/bad_encoding.go b/share/eds/byzantine/bad_encoding.go index 9ca481d552..f76ff657e1 100644 --- a/share/eds/byzantine/bad_encoding.go +++ b/share/eds/byzantine/bad_encoding.go @@ -118,7 +118,7 @@ func (p *BadEncodingProof) Validate(hdr libhead.Header) error { if header.Height() != int64(p.BlockHeight) { return errors.New("fraud: incorrect block height") } - merkleRowRoots := header.DAH.RowsRoots + merkleRowRoots := header.DAH.RowRoots merkleColRoots := header.DAH.ColumnRoots if len(merkleRowRoots) != len(merkleColRoots) { // NOTE: This should never happen as callers of this method should not feed it with a diff --git a/share/eds/byzantine/bad_encoding_test.go b/share/eds/byzantine/bad_encoding_test.go index 6604ea1e17..6e413b17a2 100644 --- a/share/eds/byzantine/bad_encoding_test.go +++ b/share/eds/byzantine/bad_encoding_test.go @@ -34,7 +34,7 @@ func TestIncorrectBadEncodingFraudProof(t *testing.T) { // get an arbitrary row row := uint(squareSize / 2) rowShares := eds.Row(row) - rowRoot := dah.RowsRoots[row] + rowRoot := dah.RowRoots[row] shareProofs, err := GetProofsForShares(ctx, bServ, ipld.MustCidFromNamespacedSha256(rowRoot), rowShares) require.NoError(t, err) diff --git a/share/eds/byzantine/byzantine.go b/share/eds/byzantine/byzantine.go index 67a6ee54c2..b9c8ef414f 100644 --- a/share/eds/byzantine/byzantine.go +++ b/share/eds/byzantine/byzantine.go @@ -36,7 +36,7 @@ func NewErrByzantine( errByz *rsmt2d.ErrByzantineData, ) *ErrByzantine { root := [][][]byte{ - dah.RowsRoots, + dah.RowRoots, dah.ColumnRoots, }[errByz.Axis][errByz.Index] sharesWithProof, err := GetProofsForShares( diff --git a/share/eds/byzantine/share_proof_test.go b/share/eds/byzantine/share_proof_test.go index 501f4b40d9..9cffe6eb18 100644 --- a/share/eds/byzantine/share_proof_test.go +++ b/share/eds/byzantine/share_proof_test.go @@ -31,7 +31,7 @@ func TestGetProof(t *testing.T) { var tests = []struct { roots [][]byte }{ - {dah.RowsRoots}, + {dah.RowRoots}, {dah.ColumnRoots}, } diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index 6fc83788eb..194f49632c 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -174,7 +174,7 @@ func TestReadEDS(t *testing.T) { loaded, err := ReadEDS(context.Background(), f, dah.Hash()) require.NoError(t, err, "error reading EDS from file") - require.Equal(t, dah.RowsRoots, loaded.RowRoots()) + require.Equal(t, dah.RowRoots, loaded.RowRoots()) require.Equal(t, dah.ColumnRoots, loaded.ColRoots()) } diff --git a/share/eds/retriever.go b/share/eds/retriever.go index 5d3c61cabb..b2dcc4ff7a 100644 --- a/share/eds/retriever.go +++ b/share/eds/retriever.go @@ -63,11 +63,11 @@ func (r *Retriever) Retrieve(ctx context.Context, dah *da.DataAvailabilityHeader ctx, span := tracer.Start(ctx, "retrieve-square") defer span.End() span.SetAttributes( - attribute.Int("size", len(dah.RowsRoots)), + attribute.Int("size", len(dah.RowRoots)), attribute.String("data_hash", dah.String()), ) - log.Debugw("retrieving data square", "data_hash", dah.String(), "size", len(dah.RowsRoots)) + log.Debugw("retrieving data square", "data_hash", dah.String(), "size", len(dah.RowRoots)) ses, err := r.newSession(ctx, dah) if err != nil { return nil, err @@ -121,7 +121,7 @@ type retrievalSession struct { // newSession creates a new retrieval session and kicks off requesting process. func (r *Retriever) newSession(ctx context.Context, dah *da.DataAvailabilityHeader) (*retrievalSession, error) { - size := len(dah.RowsRoots) + size := len(dah.RowRoots) treeFn := func(_ rsmt2d.Axis, index uint) rsmt2d.Tree { tree := wrapper.NewErasuredNamespacedMerkleTree(uint64(size)/2, index) return &tree @@ -169,12 +169,12 @@ func (rs *retrievalSession) Reconstruct(ctx context.Context) (*rsmt2d.ExtendedDa defer span.End() // and try to repair with what we have - err := rs.square.Repair(rs.dah.RowsRoots, rs.dah.ColumnRoots) + err := rs.square.Repair(rs.dah.RowRoots, rs.dah.ColumnRoots) if err != nil { span.RecordError(err) return nil, err } - log.Infow("data square reconstructed", "data_hash", rs.dah.String(), "size", len(rs.dah.RowsRoots)) + log.Infow("data square reconstructed", "data_hash", rs.dah.String(), "size", len(rs.dah.RowRoots)) close(rs.squareDn) return rs.square, nil } diff --git a/share/eds/retriever_quadrant.go b/share/eds/retriever_quadrant.go index 8b8037ce85..3d616e9cd4 100644 --- a/share/eds/retriever_quadrant.go +++ b/share/eds/retriever_quadrant.go @@ -52,7 +52,7 @@ type quadrant struct { func newQuadrants(dah *da.DataAvailabilityHeader) []*quadrant { // combine all the roots into one slice, so they can be easily accessible by index daRoots := [][][]byte{ - dah.RowsRoots, + dah.RowRoots, dah.ColumnRoots, } // create a quadrant slice for each source(row;col) diff --git a/share/eds/store.go b/share/eds/store.go index 94c86158f6..8464c7396a 100644 --- a/share/eds/store.go +++ b/share/eds/store.go @@ -276,7 +276,7 @@ func dahFromCARHeader(carHeader *carv1.CarHeader) *header.DataAvailabilityHeader rootBytes = append(rootBytes, ipld.NamespacedSha256FromCID(root)) } return &header.DataAvailabilityHeader{ - RowsRoots: rootBytes[:rootCount/2], + RowRoots: rootBytes[:rootCount/2], ColumnRoots: rootBytes[rootCount/2:], } } diff --git a/share/empty.go b/share/empty.go index 3934e9b645..10790c77fc 100644 --- a/share/empty.go +++ b/share/empty.go @@ -62,10 +62,6 @@ func EmptyExtendedDataSquare() *rsmt2d.ExtendedDataSquare { // emptyDataSquare returns the minimum size data square filled with tail padding. func emptyDataSquare() [][]byte { - result, err := shares.TailPaddingShares(appconsts.MinShareCount) - if err != nil { - panic("failed to create empty data square: " + err.Error()) - } - + result := shares.TailPaddingShares(appconsts.MinShareCount) return shares.ToBytes(result) } diff --git a/share/getter.go b/share/getter.go index 325253e974..a2b6cbf05a 100644 --- a/share/getter.go +++ b/share/getter.go @@ -52,7 +52,7 @@ type NamespacedRow struct { // Verify validates NamespacedShares by checking every row with nmt inclusion proof. func (ns NamespacedShares) Verify(root *Root, nID namespace.ID) error { originalRoots := make([][]byte, 0) - for _, row := range root.RowsRoots { + for _, row := range root.RowRoots { if !nID.Less(nmt.MinNamespace(row, nID.Size())) && nID.LessOrEqual(nmt.MaxNamespace(row, nID.Size())) { originalRoots = append(originalRoots, row) } diff --git a/share/getters/ipld.go b/share/getters/ipld.go index 5ad8c92fb2..c2f8f18f9d 100644 --- a/share/getters/ipld.go +++ b/share/getters/ipld.go @@ -54,7 +54,7 @@ func (ig *IPLDGetter) GetShare(ctx context.Context, dah *share.Root, row, col in // wrap the blockservice in a session if it has been signaled in the context. blockGetter := getGetter(ctx, ig.bServ) - s, err := share.GetShare(ctx, blockGetter, root, leaf, len(dah.RowsRoots)) + s, err := share.GetShare(ctx, blockGetter, root, leaf, len(dah.RowRoots)) if errors.Is(err, ipld.ErrNodeNotFound) { // convert error to satisfy getter interface contract err = share.ErrNotFound diff --git a/share/getters/shrex_test.go b/share/getters/shrex_test.go index 5cca0de115..47a10597ca 100644 --- a/share/getters/shrex_test.go +++ b/share/getters/shrex_test.go @@ -132,7 +132,7 @@ func newStore(t *testing.T) (*eds.Store, error) { func generateTestEDS(t *testing.T) (*rsmt2d.ExtendedDataSquare, da.DataAvailabilityHeader, nmtnamespace.ID) { eds := share.RandEDS(t, 4) dah := da.NewDataAvailabilityHeader(eds) - randNID := dah.RowsRoots[(len(dah.RowsRoots)-1)/2][:namespace.NamespaceSize] + randNID := dah.RowRoots[(len(dah.RowRoots)-1)/2][:namespace.NamespaceSize] return eds, dah, randNID } diff --git a/share/getters/store.go b/share/getters/store.go index 1c88206577..de3ffed465 100644 --- a/share/getters/store.go +++ b/share/getters/store.go @@ -57,7 +57,7 @@ func (sg *StoreGetter) GetShare(ctx context.Context, dah *share.Root, row, col i // wrap the read-only CAR blockstore in a getter blockGetter := eds.NewBlockGetter(bs) - s, err := share.GetShare(ctx, blockGetter, root, leaf, len(dah.RowsRoots)) + s, err := share.GetShare(ctx, blockGetter, root, leaf, len(dah.RowRoots)) if errors.Is(err, ipld.ErrNodeNotFound) { // convert error to satisfy getter interface contract err = share.ErrNotFound diff --git a/share/getters/utils.go b/share/getters/utils.go index 6c7c2ba7e6..c56ad01b5b 100644 --- a/share/getters/utils.go +++ b/share/getters/utils.go @@ -32,8 +32,8 @@ var ( // filterRootsByNamespace returns the row roots from the given share.Root that contain the passed // namespace ID. func filterRootsByNamespace(root *share.Root, nID namespace.ID) []cid.Cid { - rowRootCIDs := make([]cid.Cid, 0, len(root.RowsRoots)) - for _, row := range root.RowsRoots { + rowRootCIDs := make([]cid.Cid, 0, len(root.RowRoots)) + for _, row := range root.RowRoots { if !nID.Less(nmt.MinNamespace(row, nID.Size())) && nID.LessOrEqual(nmt.MaxNamespace(row, nID.Size())) { rowRootCIDs = append(rowRootCIDs, ipld.MustCidFromNamespacedSha256(row)) } @@ -68,7 +68,7 @@ func collectSharesByNamespace( // shadow loop variables, to ensure correct values are captured i, rootCID := i, rootCID errGroup.Go(func() error { - row, proof, err := share.GetSharesByNamespace(ctx, bg, rootCID, nID, len(root.RowsRoots)) + row, proof, err := share.GetSharesByNamespace(ctx, bg, rootCID, nID, len(root.RowRoots)) shares[i] = share.NamespacedRow{ Shares: row, Proof: proof, diff --git a/share/ipld/nmt.go b/share/ipld/nmt.go index 39543773b0..519ed98a02 100644 --- a/share/ipld/nmt.go +++ b/share/ipld/nmt.go @@ -172,7 +172,7 @@ func Translate(dah *da.DataAvailabilityHeader, row, col int) (cid.Cid, int) { return MustCidFromNamespacedSha256(dah.ColumnRoots[col]), row } - return MustCidFromNamespacedSha256(dah.RowsRoots[row]), col + return MustCidFromNamespacedSha256(dah.RowRoots[row]), col } // NamespacedSha256FromCID derives the Namespaced hash from the given CID. diff --git a/share/ipld/nmt_test.go b/share/ipld/nmt_test.go index cd2f22cb5b..00c10fde5d 100644 --- a/share/ipld/nmt_test.go +++ b/share/ipld/nmt_test.go @@ -34,7 +34,7 @@ func TestNamespaceFromCID(t *testing.T) { require.NoError(t, err) dah := da.NewDataAvailabilityHeader(eds) // check to make sure NamespacedHash is correctly derived from CID - for _, row := range dah.RowsRoots { + for _, row := range dah.RowRoots { c, err := CidFromNamespacedSha256(row) require.NoError(t, err) diff --git a/share/p2p/shrexnd/exchange_test.go b/share/p2p/shrexnd/exchange_test.go index e278a892e7..c2a79b1b85 100644 --- a/share/p2p/shrexnd/exchange_test.go +++ b/share/p2p/shrexnd/exchange_test.go @@ -48,7 +48,7 @@ func TestExchange_RequestND_NotFound(t *testing.T) { dah := da.NewDataAvailabilityHeader(eds) require.NoError(t, edsStore.Put(ctx, dah.Hash(), eds)) - randNID := dah.RowsRoots[(len(dah.RowsRoots)-1)/2][:namespace.NamespaceSize] + randNID := dah.RowRoots[(len(dah.RowRoots)-1)/2][:namespace.NamespaceSize] _, err := client.RequestND(ctx, &dah, randNID, server.host.ID()) require.ErrorIs(t, err, p2p.ErrNotFound) }) diff --git a/state/integration_test.go b/state/integration_test.go index 25b8e00a2d..e7d2496397 100644 --- a/state/integration_test.go +++ b/state/integration_test.go @@ -17,8 +17,8 @@ import ( "google.golang.org/grpc" "github.com/celestiaorg/celestia-app/app" - "github.com/celestiaorg/celestia-app/testutil/testfactory" - "github.com/celestiaorg/celestia-app/testutil/testnode" + "github.com/celestiaorg/celestia-app/test/util/testfactory" + "github.com/celestiaorg/celestia-app/test/util/testnode" blobtypes "github.com/celestiaorg/celestia-app/x/blob/types" "github.com/celestiaorg/celestia-node/core" From 2f49138f8023d2e73dea30685e41c33ae2487596 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Tue, 16 May 2023 12:26:46 -0400 Subject: [PATCH 26/39] fix: merge conflict --- das/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/das/worker.go b/das/worker.go index 6d85e0b202..746324ec48 100644 --- a/das/worker.go +++ b/das/worker.go @@ -150,7 +150,7 @@ func (w *worker) sample(ctx context.Context, timeout time.Duration, height uint6 "type", w.state.jobType, "height", h.Height(), "hash", h.Hash(), - "square width", len(h.DAH.RowsRoots), + "square width", len(h.DAH.RowRoots), "data root", h.DAH.String(), "finished (s)", time.Since(start), ) From c764023bb691b7f42d4f30827452de43fd4637fc Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 11:44:30 -0500 Subject: [PATCH 27/39] fix: tests --- share/availability/light/availability_test.go | 2 +- share/getters/getter_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index 9d7b3fa265..e6c665e55a 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -149,7 +149,7 @@ func TestService_GetSharesByNamespaceNotFound(t *testing.T) { root.RowRoots = nil _, err := getter.GetSharesByNamespace(context.Background(), root, namespace.RandomNamespace().Bytes()) - assert.ErrorIs(t, err, share.ErrNotFound) + assert.ErrorIs(t, err, share.ErrNamespaceNotFound) } func BenchmarkService_GetSharesByNamespace(b *testing.B) { diff --git a/share/getters/getter_test.go b/share/getters/getter_test.go index 411eb99096..c9bf82031a 100644 --- a/share/getters/getter_test.go +++ b/share/getters/getter_test.go @@ -216,7 +216,7 @@ func TestIPLDGetter(t *testing.T) { // nid not found nID = make([]byte, namespace.NamespaceSize) emptyShares, err := sg.GetSharesByNamespace(ctx, &dah, nID) - require.ErrorIs(t, err, share.ErrNotFound) + require.ErrorIs(t, err, share.ErrNamespaceNotFound) require.Nil(t, emptyShares) // nid doesnt exist in root From 2da101a251e5cb0b3b44395b649fb3f24546cdeb Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 18:08:33 -0500 Subject: [PATCH 28/39] feat!: bump app to latest main --- core/eds.go | 13 +- core/eds_test.go | 10 +- go.mod | 13 +- go.sum | 26 ++- share/availability/light/availability_test.go | 180 ------------------ share/eds/byzantine/bad_encoding.go | 7 +- share/eds/eds.go | 6 +- share/eds/eds_test.go | 73 ++++--- share/empty.go | 4 +- share/get_test.go | 9 +- share/ipld/nmt.go | 2 +- share/ipld/nmt_test.go | 9 +- share/share.go | 2 +- 13 files changed, 99 insertions(+), 255 deletions(-) diff --git a/core/eds.go b/core/eds.go index e37fa5d960..c435f0e649 100644 --- a/core/eds.go +++ b/core/eds.go @@ -7,8 +7,9 @@ import ( "github.com/filecoin-project/dagstore" "github.com/tendermint/tendermint/types" + "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/da" - appshares "github.com/celestiaorg/celestia-app/pkg/shares" + "github.com/celestiaorg/celestia-app/pkg/square" "github.com/celestiaorg/rsmt2d" "github.com/celestiaorg/celestia-node/share" @@ -22,12 +23,18 @@ func extendBlock(data types.Data) (*rsmt2d.ExtendedDataSquare, error) { if len(data.Txs) == 0 && data.SquareSize == uint64(1) { return nil, nil } - shares, err := appshares.Split(data, true) + + sqr, err := square.Construct(data.Txs.ToSliceOfBytes(), appconsts.MaxSquareSize) if err != nil { return nil, err } - return da.ExtendShares(data.SquareSize, appshares.ToBytes(shares)) + shares := make([][]byte, len(sqr)) + for i, s := range sqr { + shares[i] = s.ToBytes() + } + + return da.ExtendShares(shares) } // storeEDS will only store extended block if it is not empty and doesn't already exist. diff --git a/core/eds_test.go b/core/eds_test.go index d67f5005f9..b0e2e735a1 100644 --- a/core/eds_test.go +++ b/core/eds_test.go @@ -18,7 +18,6 @@ import ( func TestTrulyEmptySquare(t *testing.T) { data := types.Data{ Txs: []types.Tx{}, - Blobs: []types.Blob{}, SquareSize: 1, } @@ -28,16 +27,19 @@ func TestTrulyEmptySquare(t *testing.T) { } // TestNonEmptySquareWithZeroTxs tests that a non-empty square with no -// transactions or blobs computes the correct data root (not the minimum DAH). +// transactions or blobs computes the correct data root the minimum DAH. +// Technically, this block data is invalid because the construction of the +// square is deterministic, and the rules which dictate the square size do not +// allow for empty block data. However, should that ever occur, we need to to +// ensure that the correct data root is generated. func TestNonEmptySquareWithZeroTxs(t *testing.T) { data := types.Data{ Txs: []types.Tx{}, - Blobs: []types.Blob{}, SquareSize: 16, } eds, err := extendBlock(data) require.NoError(t, err) dah := da.NewDataAvailabilityHeader(eds) - assert.NotEqual(t, share.EmptyRoot().Hash(), dah.Hash()) + assert.Equal(t, share.EmptyRoot().Hash(), dah.Hash()) } diff --git a/go.mod b/go.mod index 5e4d9c9171..f75de6ca0e 100644 --- a/go.mod +++ b/go.mod @@ -9,12 +9,12 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/benbjohnson/clock v1.3.0 - github.com/celestiaorg/celestia-app v0.15.0-rc0 + github.com/celestiaorg/celestia-app v0.15.0-rc0.0.20230524155500-a9a0d36151b9 github.com/celestiaorg/go-fraud v0.1.0 github.com/celestiaorg/go-header v0.2.7 github.com/celestiaorg/go-libp2p-messenger v0.2.0 - github.com/celestiaorg/nmt v0.15.0 - github.com/celestiaorg/rsmt2d v0.8.0 + github.com/celestiaorg/nmt v0.16.0 + github.com/celestiaorg/rsmt2d v0.9.0 github.com/cosmos/cosmos-sdk v0.46.11 github.com/cosmos/cosmos-sdk/api v0.1.0 github.com/cristalhq/jwt v1.2.0 @@ -60,7 +60,7 @@ require ( github.com/pyroscope-io/otel-profiling-go v0.4.0 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.3 github.com/tendermint/tendermint v0.34.24 go.opentelemetry.io/otel v1.13.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.34.0 @@ -296,7 +296,6 @@ require ( github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/ulikunitz/xz v0.5.10 // indirect - github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect @@ -331,8 +330,8 @@ require ( ) replace ( - github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.12.0-sdk-v0.46.11 + github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v1.13.0-sdk-v0.46.11 github.com/filecoin-project/dagstore => github.com/celestiaorg/dagstore v0.0.0-20230413141458-735ab09a15d6 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.18.0-tm-v0.34.27 + github.com/tendermint/tendermint => github.com/celestiaorg/celestia-core v1.21.0-tm-v0.34.27 ) diff --git a/go.sum b/go.sum index cb8314e7a5..4d1588fd42 100644 --- a/go.sum +++ b/go.sum @@ -341,12 +341,12 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/celestiaorg/celestia-app v0.15.0-rc0 h1:LcOnih4sZ55iIUCtmIQO1UbD9Bq2R2sLWzRvgvDrAYU= -github.com/celestiaorg/celestia-app v0.15.0-rc0/go.mod h1:HEfzQx+VpvRQdwITISCTGPrbGZzfRCFhW9EzdhOXzoo= -github.com/celestiaorg/celestia-core v1.18.0-tm-v0.34.27 h1:RpwimQk/cc+2PUduPDKSwQJWI0+IpoIzQEiQIT/s1PY= -github.com/celestiaorg/celestia-core v1.18.0-tm-v0.34.27/go.mod h1:8PbX2OIPehldawXWAzNWPxBPnfFtcYtjHecE45b2Beg= -github.com/celestiaorg/cosmos-sdk v1.12.0-sdk-v0.46.11 h1:Y+/dAyu7t0F8+EZz+jU3tyZqG10W8LTCQpnHe8Ejuec= -github.com/celestiaorg/cosmos-sdk v1.12.0-sdk-v0.46.11/go.mod h1:uKEyhG8H8hbjebOEEgtyqghJWpuMyF+u61MK5cis+pk= +github.com/celestiaorg/celestia-app v0.15.0-rc0.0.20230524155500-a9a0d36151b9 h1:I1gKZDIjja7eQowtXIuwTCgMh9zehmT4CQwe8UTYkMg= +github.com/celestiaorg/celestia-app v0.15.0-rc0.0.20230524155500-a9a0d36151b9/go.mod h1:C8pNwFQWBLYIGpdrFesO1uezthrKjv0H5meecYQc1ek= +github.com/celestiaorg/celestia-core v1.21.0-tm-v0.34.27 h1:EdkqFRBypVEq/nX2ZE7KQ6dTlN8j3rEYe+WGahWuSUk= +github.com/celestiaorg/celestia-core v1.21.0-tm-v0.34.27/go.mod h1:GVo91Wifg9KL/nFx9nPkpl0UIFdvvs4fhnly9GhGxZU= +github.com/celestiaorg/cosmos-sdk v1.13.0-sdk-v0.46.11 h1:Rd5EvJx1nG3KurBspVN51RVmvif0Lp2UVURbG2ad3Cs= +github.com/celestiaorg/cosmos-sdk v1.13.0-sdk-v0.46.11/go.mod h1:xCG6OUkJy5KUMEg20Zk010lra9XjkmKS3+bk0wp7bd8= github.com/celestiaorg/dagstore v0.0.0-20230413141458-735ab09a15d6 h1:/yCwMCoOPcYCiG18u8/1pv5eXF04xczoQO3sR0bKsgM= github.com/celestiaorg/dagstore v0.0.0-20230413141458-735ab09a15d6/go.mod h1:ta/DlqIH10bvhwqJIw51Nq3QU4XVMp6pz3f0Deve9fM= github.com/celestiaorg/go-fraud v0.1.0 h1:v6mZvlmf2J5ELZfPnrtmmOvKbaYIUs/erDWPO8NbZyY= @@ -359,12 +359,12 @@ github.com/celestiaorg/go-verifcid v0.0.1-lazypatch h1:9TSe3w1cmJmbWlweCwCTIZkan github.com/celestiaorg/go-verifcid v0.0.1-lazypatch/go.mod h1:kXPYu0XqTNUKWA1h3M95UHjUqBzDwXVVt/RXZDjKJmQ= github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4 h1:CJdIpo8n5MFP2MwK0gSRcOVlDlFdQJO1p+FqdxYzmvc= github.com/celestiaorg/merkletree v0.0.0-20210714075610-a84dc3ddbbe4/go.mod h1:fzuHnhzj1pUygGz+1ZkB3uQbEUL4htqCGJ4Qs2LwMZA= -github.com/celestiaorg/nmt v0.15.0 h1:ID9QlMIeP6WK/iiGcfnYLu2qqVIq0UYe/dc3TVPt6EA= -github.com/celestiaorg/nmt v0.15.0/go.mod h1:GfwIvQPhUakn1modWxJ+rv8dUjJzuXg5H+MLFM1o7nY= +github.com/celestiaorg/nmt v0.16.0 h1:4CX6d1Uwf1C+tGcAWskPve0HCDTnI4Ey8ffjiDwcGH0= +github.com/celestiaorg/nmt v0.16.0/go.mod h1:GfwIvQPhUakn1modWxJ+rv8dUjJzuXg5H+MLFM1o7nY= github.com/celestiaorg/quantum-gravity-bridge v1.3.0 h1:9zPIp7w1FWfkPnn16y3S4FpFLnQtS7rm81CUVcHEts0= github.com/celestiaorg/quantum-gravity-bridge v1.3.0/go.mod h1:6WOajINTDEUXpSj5UZzod16UZ96ZVB/rFNKyM+Mt1gI= -github.com/celestiaorg/rsmt2d v0.8.0 h1:ZUxTCELZCM9zMGKNF3cT+rUqMddXMeiuyleSJPZ3Wn4= -github.com/celestiaorg/rsmt2d v0.8.0/go.mod h1:hhlsTi6G3+X5jOP/8Lb/d7i5y2XNFmnyMddYbFSmrgo= +github.com/celestiaorg/rsmt2d v0.9.0 h1:kon78I748ZqjNzI8OAqPN+2EImuZuanj/6gTh8brX3o= +github.com/celestiaorg/rsmt2d v0.9.0/go.mod h1:E06nDxfoeBDltWRvTR9dLviiUZI5/6mLXAuhSJzz3Iw= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= @@ -1926,8 +1926,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= @@ -1986,8 +1986,6 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 h1:zMsHhfK9+Wdl1F7sIKLyx3wrOFofpb3rWFbA4HgcK5k= -github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3/go.mod h1:R0Gbuw7ElaGSLOZUSwBm/GgVwMd30jWxBDdAyMOeTuc= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= diff --git a/share/availability/light/availability_test.go b/share/availability/light/availability_test.go index e6c665e55a..4980af031e 100644 --- a/share/availability/light/availability_test.go +++ b/share/availability/light/availability_test.go @@ -1,23 +1,16 @@ package light import ( - "bytes" "context" - "crypto/rand" _ "embed" - "encoding/json" - mrand "math/rand" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - core "github.com/tendermint/tendermint/types" "github.com/celestiaorg/celestia-app/pkg/da" "github.com/celestiaorg/celestia-app/pkg/namespace" - appshares "github.com/celestiaorg/celestia-app/pkg/shares" "github.com/celestiaorg/celestia-node/header" "github.com/celestiaorg/celestia-node/share" @@ -175,176 +168,3 @@ func BenchmarkService_GetSharesByNamespace(b *testing.B) { }) } } - -func TestSharesRoundTrip(t *testing.T) { - getter, store := EmptyGetter() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - var pb tmproto.Block - err := json.Unmarshal([]byte(sampleBlock), &pb) - require.NoError(t, err) - - b, err := core.BlockFromProto(&pb) - require.NoError(t, err) - - namespaceA := namespace.MustNewV0(bytes.Repeat([]byte{0xa}, namespace.NamespaceVersionZeroIDSize)) - namespaceB := namespace.MustNewV0(bytes.Repeat([]byte{0xb}, namespace.NamespaceVersionZeroIDSize)) - namespaceC := namespace.MustNewV0(bytes.Repeat([]byte{0xc}, namespace.NamespaceVersionZeroIDSize)) - - type testCase struct { - name string - messages [][]byte - namespaces []namespace.Namespace - } - - cases := []testCase{ - { - "original test case", - [][]byte{b.Data.Blobs[0].Data}, - []namespace.Namespace{namespaceB}}, - { - "one short message", - [][]byte{{1, 2, 3, 4}}, - []namespace.Namespace{namespaceB}}, - { - "one short before other namespace", - [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}}, - []namespace.Namespace{namespaceB, namespaceC}, - }, - { - "one short after other namespace", - [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}}, - []namespace.Namespace{namespaceA, namespaceB}, - }, - { - "two short messages", - [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}}, - []namespace.Namespace{namespaceB, namespaceB}, - }, - { - "two short messages before other namespace", - [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}, {7, 8, 9}}, - []namespace.Namespace{namespaceB, namespaceB, namespaceC}, - }, - { - "two short messages after other namespace", - [][]byte{{1, 2, 3, 4}, {4, 5, 6, 7}, {7, 8, 9}}, - []namespace.Namespace{namespaceA, namespaceB, namespaceB}, - }, - } - randBytes := func(n int) []byte { - bs := make([]byte, n) - _, _ = rand.Read(bs) - return bs - } - for i := 128; i < 4192; i += mrand.Intn(256) { - l := strconv.Itoa(i) - cases = append(cases, testCase{ - "one " + l + " bytes message", - [][]byte{randBytes(i)}, - []namespace.Namespace{namespaceB}, - }) - cases = append(cases, testCase{ - "one " + l + " bytes before other namespace", - [][]byte{randBytes(i), randBytes(1 + mrand.Intn(i))}, - []namespace.Namespace{namespaceB, namespaceC}, - }) - cases = append(cases, testCase{ - "one " + l + " bytes after other namespace", - [][]byte{randBytes(1 + mrand.Intn(i)), randBytes(i)}, - []namespace.Namespace{namespaceA, namespaceB}, - }) - cases = append(cases, testCase{ - "two " + l + " bytes messages", - [][]byte{randBytes(i), randBytes(i)}, - []namespace.Namespace{namespaceB, namespaceB}, - }) - cases = append(cases, testCase{ - "two " + l + " bytes messages before other namespace", - [][]byte{randBytes(i), randBytes(i), randBytes(1 + mrand.Intn(i))}, - []namespace.Namespace{namespaceB, namespaceB, namespaceC}, - }) - cases = append(cases, testCase{ - "two " + l + " bytes messages after other namespace", - [][]byte{randBytes(1 + mrand.Intn(i)), randBytes(i), randBytes(i)}, - []namespace.Namespace{namespaceA, namespaceB, namespaceB}, - }) - } - - for _, tc := range cases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - // prepare data - b.Data.Blobs = make([]core.Blob, len(tc.messages)) - b.SquareSize = 16 - var msgsInNamespace [][]byte - require.Equal(t, len(tc.namespaces), len(tc.messages)) - for i := range tc.messages { - b.Data.Blobs[i] = core.Blob{ - NamespaceID: tc.namespaces[i].ID, - Data: tc.messages[i], - NamespaceVersion: tc.namespaces[i].Version, - } - if bytes.Equal(tc.namespaces[i].Bytes(), namespaceB.Bytes()) { - msgsInNamespace = append(msgsInNamespace, tc.messages[i]) - } - } - - // TODO: set useShareIndexes to true. This requires updating the - // transaction data in this test to include share indexes. - shares, err := appshares.Split(b.Data, false) - if err != nil { - t.Fatal(err) - } - - // test round trip using only encoding, without IPLD - { - myShares := make([][]byte, 0) - for _, sh := range shares { - ns, err := sh.Namespace() - require.NoError(t, err) - if bytes.Equal(namespaceB.Bytes(), ns.Bytes()) { - myShares = append(myShares, sh.ToBytes()) - } - } - appShares, err := appshares.FromBytes(myShares) - assert.NoError(t, err) - blobs, err := appshares.ParseBlobs(appShares) - require.NoError(t, err) - assert.Len(t, blobs, len(msgsInNamespace)) - for i := range blobs { - assert.Equal(t, msgsInNamespace[i], blobs[i].Data) - } - } - - // test full round trip - with IPLD + decoding shares - { - extSquare, err := share.AddShares(ctx, appshares.ToBytes(shares), store) - require.NoError(t, err) - - dah := da.NewDataAvailabilityHeader(extSquare) - shares, err := getter.GetSharesByNamespace(ctx, &dah, namespaceB.Bytes()) - require.NoError(t, err) - require.NoError(t, shares.Verify(&dah, namespaceB.Bytes())) - require.NotEmpty(t, shares) - - appShares, err := appshares.FromBytes(shares.Flatten()) - assert.NoError(t, err) - blobs, err := appshares.ParseBlobs(appShares) - require.NoError(t, err) - assert.Len(t, blobs, len(msgsInNamespace)) - for i := range blobs { - assert.Equal(t, namespaceB.ID, blobs[i].NamespaceID) - assert.Equal(t, namespaceB.Version, blobs[i].NamespaceVersion) - assert.Equal(t, msgsInNamespace[i], blobs[i].Data) - } - } - }) - } -} - -// this is a sample block -// -//go:embed "testdata/sample-block.json" -var sampleBlock string diff --git a/share/eds/byzantine/bad_encoding.go b/share/eds/byzantine/bad_encoding.go index f76ff657e1..7e2c395c48 100644 --- a/share/eds/byzantine/bad_encoding.go +++ b/share/eds/byzantine/bad_encoding.go @@ -175,8 +175,13 @@ func (p *BadEncodingProof) Validate(hdr libhead.Header) error { tree.Push(share) } + expectedRoot, err := tree.Root() + if err != nil { + return err + } + // comparing rebuilt Merkle Root of bad row/col with respective Merkle Root of row/col from block. - if bytes.Equal(tree.Root(), root) { + if bytes.Equal(expectedRoot, root) { return errors.New("fraud: invalid proof: recomputed Merkle root matches the DAH's row/column root") } diff --git a/share/eds/eds.go b/share/eds/eds.go index 0f69745879..5bd8ad499b 100644 --- a/share/eds/eds.go +++ b/share/eds/eds.go @@ -18,6 +18,7 @@ import ( "github.com/ipld/go-car/util" "github.com/minio/sha256-simd" + "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/da" "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/celestia-app/pkg/wrapper" @@ -219,11 +220,12 @@ func getQuadrantCells(eds *rsmt2d.ExtendedDataSquare, i, j uint) [][]byte { // prependNamespace adds the namespace to the passed share if in the first quadrant, // otherwise it adds the ParitySharesNamespace to the beginning. func prependNamespace(quadrant int, share []byte) []byte { + r := make([]byte, 0, appconsts.NamespaceSize+appconsts.ShareSize) switch quadrant { case 0: - return append(share[:ipld.NamespaceSize], share...) + return append(append(r, share[:ipld.NamespaceSize]...), share...) case 1, 2, 3: - return append(namespace.ParitySharesNamespace.Bytes(), share...) + return append(append(r, namespace.ParitySharesNamespace.Bytes()...), share...) default: panic("invalid quadrant") } diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index 194f49632c..1038fd4496 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -14,7 +14,9 @@ import ( carv1 "github.com/ipld/go-car" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/rand" + "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/da" "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/rsmt2d" @@ -30,36 +32,47 @@ var exampleRoot string var f embed.FS func TestQuadrantOrder(t *testing.T) { - // TODO: add more test cases - nID := bytes.Repeat([]byte{0}, namespace.NamespaceSize) - result, _ := rsmt2d.ComputeExtendedDataSquare([][]byte{ - append(nID, 1), append(nID, 2), - append(nID, 3), append(nID, 4), - }, rsmt2d.NewRSGF8Codec(), rsmt2d.NewDefaultTree) - // {{1}, {2}, {7}, {13}}, - // {{3}, {4}, {13}, {31}}, - // {{5}, {14}, {19}, {41}}, - // {{9}, {26}, {47}, {69}}, - require.Equal(t, - [][]byte{ - append(append(nID, nID...), 1), - append(append(nID, nID...), 2), - append(append(nID, nID...), 3), - append(append(nID, nID...), 4), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 7), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 13), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 13), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 31), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 5), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 14), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 9), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 26), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 19), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 41), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 47), - append(append(namespace.ParitySharesNamespace.Bytes(), nID...), 69), - }, quadrantOrder(result), - ) + testCases := []struct { + name string + squareSize int + }{ + {"smol", 2}, + {"still smol", 8}, + {"default mainnet", appconsts.DefaultGovMaxSquareSize}, + {"max", appconsts.MaxSquareSize}, + } + + testShareSize := 64 + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + shares := make([][]byte, tc.squareSize*tc.squareSize) + + for i := 0; i < tc.squareSize*tc.squareSize; i++ { + shares[i] = append(make([]byte, 0, testShareSize), rand.Bytes(testShareSize)...) + } + + eds, err := rsmt2d.ComputeExtendedDataSquare(shares, appconsts.DefaultCodec(), rsmt2d.NewDefaultTree) + require.NoError(t, err) + + res := quadrantOrder(eds) + for _, s := range res { + require.Len(t, s, testShareSize+namespace.NamespaceSize) + } + + for q := 0; q < 4; q++ { + for i := 0; i < tc.squareSize; i++ { + for j := 0; j < tc.squareSize; j++ { + resIndex := q*tc.squareSize*tc.squareSize + i*tc.squareSize + j + edsRow := q/2*tc.squareSize + i + edsCol := (q%2)*tc.squareSize + j + + assert.Equal(t, res[resIndex], prependNamespace(q, eds.Row(uint(edsRow))[edsCol])) + } + } + } + }) + } } func TestWriteEDS(t *testing.T) { diff --git a/share/empty.go b/share/empty.go index 10790c77fc..b5a8b11041 100644 --- a/share/empty.go +++ b/share/empty.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "math" "github.com/ipfs/go-blockservice" @@ -22,8 +21,7 @@ var ( func init() { // compute empty block EDS and DAH for it shares := emptyDataSquare() - squareSize := uint64(math.Sqrt(float64(appconsts.DefaultMinSquareSize))) - eds, err := da.ExtendShares(squareSize, shares) + eds, err := da.ExtendShares(shares) if err != nil { panic(fmt.Errorf("failed to create empty EDS: %w", err)) } diff --git a/share/get_test.go b/share/get_test.go index 0ea83fd178..fca1998141 100644 --- a/share/get_test.go +++ b/share/get_test.go @@ -18,6 +18,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/wrapper" "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" @@ -75,7 +76,7 @@ func TestBlockRecovery(t *testing.T) { t.Run(tc.name, func(t *testing.T) { squareSize := utils.SquareSize(len(tc.shares)) - eds, err := rsmt2d.ComputeExtendedDataSquare(tc.shares, rsmt2d.NewRSGF8Codec(), wrapper.NewConstructor(squareSize)) + eds, err := rsmt2d.ComputeExtendedDataSquare(tc.shares, appconsts.DefaultCodec(), wrapper.NewConstructor(squareSize)) require.NoError(t, err) // calculate roots using the first complete square @@ -88,7 +89,7 @@ func TestBlockRecovery(t *testing.T) { rdata := removeRandShares(flat, tc.d) eds, err = rsmt2d.ImportExtendedDataSquare( rdata, - rsmt2d.NewRSGF8Codec(), + appconsts.DefaultCodec(), wrapper.NewConstructor(squareSize), ) require.NoError(t, err) @@ -101,7 +102,7 @@ func TestBlockRecovery(t *testing.T) { } assert.NoError(t, err) - reds, err := rsmt2d.ImportExtendedDataSquare(rdata, rsmt2d.NewRSGF8Codec(), wrapper.NewConstructor(squareSize)) + reds, err := rsmt2d.ImportExtendedDataSquare(rdata, appconsts.DefaultCodec(), wrapper.NewConstructor(squareSize)) require.NoError(t, err) // check that the squares are equal assert.Equal(t, ExtractEDS(eds), ExtractEDS(reds)) @@ -116,7 +117,7 @@ func Test_ConvertEDStoShares(t *testing.T) { // compute extended square eds, err := rsmt2d.ComputeExtendedDataSquare( shares, - rsmt2d.NewRSGF8Codec(), + appconsts.DefaultCodec(), wrapper.NewConstructor(uint64(squareWidth)), ) require.NoError(t, err) diff --git a/share/ipld/nmt.go b/share/ipld/nmt.go index 519ed98a02..e5e7d41cd1 100644 --- a/share/ipld/nmt.go +++ b/share/ipld/nmt.go @@ -40,7 +40,7 @@ const ( // MaxSquareSize is currently the maximum size supported for unerasured data in // rsmt2d.ExtendedDataSquare. - MaxSquareSize = appconsts.DefaultMaxSquareSize + MaxSquareSize = appconsts.MaxSquareSize // NamespaceSize is a system-wide size for NMT namespaces. NamespaceSize = appconsts.NamespaceSize diff --git a/share/ipld/nmt_test.go b/share/ipld/nmt_test.go index 00c10fde5d..b52a75c150 100644 --- a/share/ipld/nmt_test.go +++ b/share/ipld/nmt_test.go @@ -12,8 +12,6 @@ import ( "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/da" - - "github.com/celestiaorg/celestia-node/libs/utils" ) // TestNamespaceFromCID checks that deriving the Namespaced hash from @@ -22,6 +20,7 @@ func TestNamespaceFromCID(t *testing.T) { var tests = []struct { randData [][]byte }{ + // note that the number of shares must be a power of two {randData: generateRandNamespacedRawData(4, appconsts.NamespaceSize, appconsts.ShareSize-appconsts.NamespaceSize)}, {randData: generateRandNamespacedRawData(16, appconsts.NamespaceSize, appconsts.ShareSize-appconsts.NamespaceSize)}, } @@ -29,8 +28,7 @@ func TestNamespaceFromCID(t *testing.T) { for i, tt := range tests { t.Run(strconv.Itoa(i), func(t *testing.T) { // create DAH from rand data - squareSize := utils.SquareSize(len(tt.randData)) - eds, err := da.ExtendShares(squareSize, tt.randData) + eds, err := da.ExtendShares(tt.randData) require.NoError(t, err) dah := da.NewDataAvailabilityHeader(eds) // check to make sure NamespacedHash is correctly derived from CID @@ -45,7 +43,8 @@ func TestNamespaceFromCID(t *testing.T) { } } -// generateRandNamespacedRawData returns random namespaced raw data for testing purposes. +// generateRandNamespacedRawData returns random namespaced raw data for testing +// purposes. Note that this does not check that total is a power of two. func generateRandNamespacedRawData(total, nidSize, leafSize uint32) [][]byte { data := make([][]byte, total) for i := uint32(0); i < total; i++ { diff --git a/share/share.go b/share/share.go index 643f0c477a..06f911636d 100644 --- a/share/share.go +++ b/share/share.go @@ -20,7 +20,7 @@ var ( const ( // MaxSquareSize is currently the maximum size supported for unerasured data in // rsmt2d.ExtendedDataSquare. - MaxSquareSize = appconsts.DefaultMaxSquareSize + MaxSquareSize = appconsts.MaxSquareSize // NamespaceSize is a system-wide size for NMT namespaces. NamespaceSize = appconsts.NamespaceSize // Size is a system-wide size of a share, including both data and namespace ID From 80964fdd6d0d1047825db777156fb5902f88cb04 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 18:59:25 -0500 Subject: [PATCH 29/39] fix: tests --- api/gateway/share.go | 3 + api/gateway/share_test.go | 136 ++++++--------------------- share/eds/testdata/example-root.json | 32 +++---- share/eds/testdata/example.car | Bin 77635 -> 74051 bytes 4 files changed, 50 insertions(+), 121 deletions(-) diff --git a/api/gateway/share.go b/api/gateway/share.go index 36a9778f1a..370a991742 100644 --- a/api/gateway/share.go +++ b/api/gateway/share.go @@ -127,15 +127,18 @@ func dataFromShares(input []share.Share) (data [][]byte, err error) { if err != nil { return nil, err } + fmt.Println("len sharse", len(appShares)) sequences, err := shares.ParseShares(appShares, false) if err != nil { return nil, err } + fmt.Println("len sequences", len(sequences)) for _, sequence := range sequences { raw, err := sequence.RawData() if err != nil { return nil, err } + fmt.Println("len raw", len(raw), "raw", string(raw)) data = append(data, raw) } return data, nil diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index 88eaac279e..51b4ef2b1b 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -2,124 +2,50 @@ package gateway import ( "bytes" + "fmt" "testing" - "github.com/stretchr/testify/assert" - "github.com/celestiaorg/celestia-app/pkg/appconsts" + "github.com/celestiaorg/celestia-app/pkg/namespace" + "github.com/celestiaorg/celestia-app/pkg/shares" + "github.com/stretchr/testify/require" + coretypes "github.com/tendermint/tendermint/types" ) func Test_dataFromShares(t *testing.T) { - type testCase struct { - name string - input [][]byte - want [][]byte - wantErr bool + input := [][]byte{ + []byte("beep"), + []byte("beeap"), + []byte("BEEEEAHP"), } - smallTxInput := padShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace - 0x1, // info byte - 0x0, 0x0, 0x0, 0x2, // 1 byte (unit) + 1 byte (unit length) = 2 bytes sequence length - 0x0, 0x0, 0x0, 0x2a, // reserved bytes - 0x1, // unit length of first transaction - 0xa, // data of first transaction - }) - smallTxData := []byte{0x1, 0xa} - - largeTxInput := [][]byte{ - fillShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace - 0x1, // info byte - 0x0, 0x0, 0x2, 0x2, // 512 (unit) + 2 (unit length) = 514 sequence length - 0x0, 0x0, 0x0, 0x2a, // reserved bytes - 128, 4, // unit length of transaction is 512 - }, 0xc), // data of transaction - padShare(append([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // namespace - 0x0, // info byte - 0x0, 0x0, 0x0, 0x0, // reserved bytes - }, bytes.Repeat([]byte{0xc}, 44)..., // continuation data of transaction - )), + ns := namespace.RandomBlobNamespace() + sss := shares.NewSparseShareSplitter() + for _, i := range input { + b := coretypes.Blob{ + Data: i, + NamespaceID: ns.Bytes()[1:], + NamespaceVersion: namespace.NamespaceVersionZero, + ShareVersion: appconsts.ShareVersionZero, + } + err := sss.Write(b) + require.NoError(t, err) } - largeTxData := []byte{128, 4} - largeTxData = append(largeTxData, bytes.Repeat([]byte{0xc}, 512)...) - largePfbTxInput := [][]byte{ - fillShare([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace - 0x1, // info byte - 0x0, 0x0, 0x2, 0x2, // 512 (unit) + 2 (unit length) = 514 sequence length - 0x0, 0x0, 0x0, 0x2a, // reserved bytes - 128, 4, // unit length of transaction is 512 - }, 0xc), // data of transaction - padShare(append([]uint8{ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // namespace - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, // namespace - 0x0, // info byte - 0x0, 0x0, 0x0, 0x0, // reserved bytes - }, bytes.Repeat([]byte{0xc}, 44)..., // continuation data of transaction - )), - } - largePfbTxData := []byte{128, 4} - largePfbTxData = append(largePfbTxData, bytes.Repeat([]byte{0xc}, 512)...) + sssShares := sss.Export() - testCases := []testCase{ - { - name: "empty", - input: [][]byte{}, - want: nil, - wantErr: false, - }, - { - name: "returns an error when shares contain two different namespaces", - input: [][]byte{ - { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - }, - { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - }, - }, - want: nil, - wantErr: true, - }, - { - name: "returns raw data of a single tx share", - input: [][]byte{smallTxInput}, - want: [][]byte{smallTxData}, - wantErr: false, - }, - { - name: "returns raw data of a large tx that spans two shares", - input: largeTxInput, - want: [][]byte{largeTxData}, - wantErr: false, - }, - { - name: "returns raw data of a large PFB tx that spans two shares", - input: largePfbTxInput, - want: [][]byte{largePfbTxData}, - wantErr: false, - }, - } + fmt.Println("exported shares: ", sssShares) - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - got, err := dataFromShares(tc.input) - if tc.wantErr { - assert.Error(t, err) - return - } - assert.Equal(t, tc.want, got) - }) + rawSSSShares := make([][]byte, len(sssShares)) + for i := 0; i < len(sssShares); i++ { + d := sssShares[i].ToBytes() + rawSSSShares[i] = d } + + parsedSSSShares, err := dataFromShares(rawSSSShares) + require.NoError(t, err) + + require.Equal(t, input, parsedSSSShares) } // padShare returns a share padded with trailing zeros. diff --git a/share/eds/testdata/example-root.json b/share/eds/testdata/example-root.json index a0528724e1..999d6301b6 100644 --- a/share/eds/testdata/example-root.json +++ b/share/eds/testdata/example-root.json @@ -1,22 +1,22 @@ { "row_roots": [ -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHTFhSx3pL2TzSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA471vB8w31XZHnopsd0qqnrIfVzBnaeUwwhrSzNvBV0VV+fR488sbA3k4=", -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9ATJz7IJ2eM8xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFKeOh475dZe0/Sd7d/YZvijcIvVboK9IXySOx474M8uikVOpsWToXqKI=", -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOVNPdVhe/rBupAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDbUgoGqCZAcODs0JB2nUgKgyHosKtd27RgrzElkzpu/M7HwcZpBuN3ck=", -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADK2Puw1bjVnqxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvv3LXXLy+ptlfTSiXfBAVffz1aP1ZXnZX8OrFEcnGEHraUqFFHNzzFgM=", -"////////////////////////////////////////////////////////////////////////////////////////z7oU9k16pSH9Pjp6HBD9c15+R9f/3Gh8pP5EhXT+0hI=", -"////////////////////////////////////////////////////////////////////////////////////////EiImqkkAlJ9byWVpiEM30Xf8hGHf5fkCiLPK/J7tugY=", -"////////////////////////////////////////////////////////////////////////////////////////kJTZhKJhjZNXAaqev1YY7kPYO1O049gEPkQOA8uLwgs=", -"////////////////////////////////////////////////////////////////////////////////////////0hNW6Fc/UzAxUlvmEgrHY+p/A/ihwrb7p8x6DciPcFc=" +"AAAAAAAAAAAAAAAAAAAAAAAAABPYEuDlO9Dz69oAAAAAAAAAAAAAAAAAAAAAAAAAMcklN0h38T4b/UBC/Cmr5YWmjmmxvi1e35vZBW14b8gDHBoTFVvY6H4J", +"AAAAAAAAAAAAAAAAAAAAAAAAADxyZecUZD41W5IAAAAAAAAAAAAAAAAAAAAAAAAAh8vQUZ38PaWyeUs7dQhphIuRIKiGaTr4KFwEhMRhejTd6/4NHdnKTDyY", +"AAAAAAAAAAAAAAAAAAAAAAAAAKDQatbQSwQ9uJsAAAAAAAAAAAAAAAAAAAAAAAAArtdqXCSsM1OlVCRZqqfZDnEO9eC5cwlgy5MQHb2g4NLr7nZYTruiOoz7", +"AAAAAAAAAAAAAAAAAAAAAAAAAMeUhM8LZBo9sWwAAAAAAAAAAAAAAAAAAAAAAAAA8PtvJpbDc4APKOK6MT1k61HuQXwauWw3nFWwr9pSljiYMv6jjjdLDF8o", +"/////////////////////////////////////////////////////////////////////////////xnHmhDh4Y8vfJrgewAcvLWpvI5XOyATj1IQDkCwvIEh", +"/////////////////////////////////////////////////////////////////////////////+qngp0AfoykfXwsMBukRtYxNA/bzW0+F3J7Q/+S1YZJ", +"/////////////////////////////////////////////////////////////////////////////4WNPrME/2MLrIZgAUoKaVx2GzJqDcYGrBg+sudPKUDy", +"/////////////////////////////////////////////////////////////////////////////6HdebpaHl7iTpLvmuPvtQNnkHfNOPyEhahxbVnIB2d1" ], "column_roots": [ -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHTFhSx3pL2TzSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADK2Puw1bjVnqxtmfyp21ILskj/RLG+SDEnchdtrB5SpmNwKuzvoUC6gR4=", -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANsHwL6Ob9gV8pAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADPGTFJynN6qsCNGFem7/MTUzx/toLJsXscN3Us53aVstRjSncLITykF4U=", -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtgFZuc6+HTef8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADtzesBmtJVQvUnB3winMTo9pRt/V5QokHHR50UFtFr++3pIXCkplNg4cQ=", -"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA471vB8w31XZHnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvv3LXXLy+ptlfewqsRMxxtS1UajvtBS2mboLWqzY7FqE36Vke8SAjrAg=", -"////////////////////////////////////////////////////////////////////////////////////////ypfKr/j2SbwNvnS+kHAR+8QyQamzicQJnYRAvdWHfIM=", -"////////////////////////////////////////////////////////////////////////////////////////zFU3LQr1phGO10/Yld5kUmQTAWPHs5SHnChaVmis0Xk=", -"////////////////////////////////////////////////////////////////////////////////////////PvBBi1eB8yy3poz4sn6UzV5zcg9r0xjU8lmqgKRZFBU=", -"/////////////////////////////////////////////////////////////////////////////////////////2ejiT2RxUy1tyaJ8QBByb32SgB0VpSWQ8baEHDEJI0=" +"AAAAAAAAAAAAAAAAAAAAAAAAABPYEuDlO9Dz69oAAAAAAAAAAAAAAAAAAAAAAAAAx5SEzwtkGj2xbESyOeamsjGWUBQdAQoiSl+rMtNMo1wEtfGQnFS/g+K+", +"AAAAAAAAAAAAAAAAAAAAAAAAAC3uK6nhCxHTfBwAAAAAAAAAAAAAAAAAAAAAAAAA1fxnqHyO6qV39pcUQ8MuTfJ7RBhbSVWf0aamUP27KRY0II55oJoY6Ng6", +"AAAAAAAAAAAAAAAAAAAAAAAAAC6DkYeeBY/kKvAAAAAAAAAAAAAAAAAAAAAAAAAA47rxk8hoCnWGM+CX47TlYWBeE2unvRhA/j3EvHdxeL1rFRkaYfAd5eg7", +"AAAAAAAAAAAAAAAAAAAAAAAAADHJJTdId/E+G/0AAAAAAAAAAAAAAAAAAAAAAAAA8PtvJpbDc4APKAk5QPSH59HECE2sf/CDLKAZJjWo9DD4sLXJQ4jTZoH6", +"/////////////////////////////////////////////////////////////////////////////4lKCT3K11RnNIuLNfY+SfDZCYAE2iW0hjQHIVBpoN0q", +"/////////////////////////////////////////////////////////////////////////////1NpYcgayEVenbFeEO5LJ1j1/1sD+PvZWHDv+jqT1dLR", +"/////////////////////////////////////////////////////////////////////////////8FOWVuCU0rTzUW9tP2R47RmTBvwXX8ycKrMhgKEi1xa", +"/////////////////////////////////////////////////////////////////////////////7K5SoZ3HF5QgPvIXpKSr9eT4Xfiokc3PUMmXE4pBDTf" ] } \ No newline at end of file diff --git a/share/eds/testdata/example.car b/share/eds/testdata/example.car index 6f68eac0bf9afccbab12ad576f409494c13be4d6..4d33c0ef33300d68c8f3a05f7e09c65409c30b9d 100644 GIT binary patch literal 74051 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
+WMn=G?azFh_o`B4HP{apfoD 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 qiuVJ<0z#yd3DBVn=DK5HP8Xz#X>{mVnAk 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 From 727f946776242ba3f917b3a833ee9bd07c7fe3ec Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 19:18:37 -0500 Subject: [PATCH 30/39] fix: linter --- share/eds/byzantine/bad_encoding.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/eds/byzantine/bad_encoding.go b/share/eds/byzantine/bad_encoding.go index 7e2c395c48..3f7fab1d80 100644 --- a/share/eds/byzantine/bad_encoding.go +++ b/share/eds/byzantine/bad_encoding.go @@ -172,7 +172,10 @@ func (p *BadEncodingProof) Validate(hdr libhead.Header) error { tree := wrapper.NewErasuredNamespacedMerkleTree(odsWidth, uint(p.Index)) for _, share := range rebuiltShares { - tree.Push(share) + err = tree.Push(share) + if err != nil { + return err + } } expectedRoot, err := tree.Root() From 3d9d77734c70b6dec38a5ecbaba0cd3a030ff311 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 19:38:50 -0500 Subject: [PATCH 31/39] chore: bump tag --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f75de6ca0e..abdc7b6afc 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/benbjohnson/clock v1.3.0 - github.com/celestiaorg/celestia-app v0.15.0-rc0.0.20230524155500-a9a0d36151b9 + github.com/celestiaorg/celestia-app v1.0.0-rc0 github.com/celestiaorg/go-fraud v0.1.0 github.com/celestiaorg/go-header v0.2.7 github.com/celestiaorg/go-libp2p-messenger v0.2.0 diff --git a/go.sum b/go.sum index 4d1588fd42..9eca643fef 100644 --- a/go.sum +++ b/go.sum @@ -341,8 +341,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/celestiaorg/celestia-app v0.15.0-rc0.0.20230524155500-a9a0d36151b9 h1:I1gKZDIjja7eQowtXIuwTCgMh9zehmT4CQwe8UTYkMg= -github.com/celestiaorg/celestia-app v0.15.0-rc0.0.20230524155500-a9a0d36151b9/go.mod h1:C8pNwFQWBLYIGpdrFesO1uezthrKjv0H5meecYQc1ek= +github.com/celestiaorg/celestia-app v1.0.0-rc0 h1:wpuP5fTIEbLCP+U5pGwKfSzXUTE/bE8oqKECFN5yoO0= +github.com/celestiaorg/celestia-app v1.0.0-rc0/go.mod h1:C8pNwFQWBLYIGpdrFesO1uezthrKjv0H5meecYQc1ek= github.com/celestiaorg/celestia-core v1.21.0-tm-v0.34.27 h1:EdkqFRBypVEq/nX2ZE7KQ6dTlN8j3rEYe+WGahWuSUk= github.com/celestiaorg/celestia-core v1.21.0-tm-v0.34.27/go.mod h1:GVo91Wifg9KL/nFx9nPkpl0UIFdvvs4fhnly9GhGxZU= github.com/celestiaorg/cosmos-sdk v1.13.0-sdk-v0.46.11 h1:Rd5EvJx1nG3KurBspVN51RVmvif0Lp2UVURbG2ad3Cs= From a52164f02eb049eadbd522ce9931164cc27ed6cc Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 20:38:43 -0500 Subject: [PATCH 32/39] fix: linter --- api/gateway/share_test.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index 51b4ef2b1b..1c6d7cea17 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -1,7 +1,6 @@ package gateway import ( - "bytes" "fmt" "testing" @@ -47,14 +46,3 @@ func Test_dataFromShares(t *testing.T) { require.Equal(t, input, parsedSSSShares) } - -// padShare returns a share padded with trailing zeros. -func padShare(share []byte) (paddedShare []byte) { - return fillShare(share, 0) -} - -// fillShare returns a share filled with filler so that the share length -// is equal to appconsts.ShareSize. -func fillShare(share []byte, filler byte) (paddedShare []byte) { - return append(share, bytes.Repeat([]byte{filler}, appconsts.ShareSize-len(share))...) -} From 74da56745814fbe34af0592e4aad59f76da28cb5 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 24 May 2023 21:09:47 -0500 Subject: [PATCH 33/39] chore: cleanup --- api/gateway/share.go | 3 --- api/gateway/share_test.go | 3 --- 2 files changed, 6 deletions(-) diff --git a/api/gateway/share.go b/api/gateway/share.go index 370a991742..36a9778f1a 100644 --- a/api/gateway/share.go +++ b/api/gateway/share.go @@ -127,18 +127,15 @@ func dataFromShares(input []share.Share) (data [][]byte, err error) { if err != nil { return nil, err } - fmt.Println("len sharse", len(appShares)) sequences, err := shares.ParseShares(appShares, false) if err != nil { return nil, err } - fmt.Println("len sequences", len(sequences)) for _, sequence := range sequences { raw, err := sequence.RawData() if err != nil { return nil, err } - fmt.Println("len raw", len(raw), "raw", string(raw)) data = append(data, raw) } return data, nil diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index 1c6d7cea17..b97de7f290 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -1,7 +1,6 @@ package gateway import ( - "fmt" "testing" "github.com/celestiaorg/celestia-app/pkg/appconsts" @@ -33,8 +32,6 @@ func Test_dataFromShares(t *testing.T) { sssShares := sss.Export() - fmt.Println("exported shares: ", sssShares) - rawSSSShares := make([][]byte, len(sssShares)) for i := 0; i < len(sssShares); i++ { d := sssShares[i].ToBytes() From 7c17cbc2b8357f00b2869955d8075a3fa1252639 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 25 May 2023 09:22:03 -0500 Subject: [PATCH 34/39] chore: remove unnecessary append --- share/eds/eds_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index 1038fd4496..8859c753b7 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -49,7 +49,7 @@ func TestQuadrantOrder(t *testing.T) { shares := make([][]byte, tc.squareSize*tc.squareSize) for i := 0; i < tc.squareSize*tc.squareSize; i++ { - shares[i] = append(make([]byte, 0, testShareSize), rand.Bytes(testShareSize)...) + shares[i] = rand.Bytes(testShareSize) } eds, err := rsmt2d.ComputeExtendedDataSquare(shares, appconsts.DefaultCodec(), rsmt2d.NewDefaultTree) From 01bbd0dd8abf08d95ae07e78ae464cafa3557c0f Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 25 May 2023 09:24:51 -0500 Subject: [PATCH 35/39] chore: remove unused testdata --- .../light/testdata/sample-block.json | 60 ------------------- 1 file changed, 60 deletions(-) delete mode 100755 share/availability/light/testdata/sample-block.json diff --git a/share/availability/light/testdata/sample-block.json b/share/availability/light/testdata/sample-block.json deleted file mode 100755 index 2bb8d35bfb..0000000000 --- a/share/availability/light/testdata/sample-block.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "header": { - "version": { - "block": 11 - }, - "chain_id": "7sUWGE", - "height": 12, - "time": "2023-01-19T01:41:20.109585974Z", - "last_block_id": { - "hash": "MfZsPUTgVOBRak+3xnKdwWEr2NQ1v095T4BYaWcdYTs=", - "part_set_header": { - "total": 1, - "hash": "/qyxxHNcuOyYBcaGw90PqAa2GdFErMHkkbH66BDI1hI=" - } - }, - "last_commit_hash": "sQXqALyCQ+tHFKOjfQhB3+lQuud0d3C2ohuOgrO6YX4=", - "data_hash": "Pu8CIJqgqCFYkaSvfeS5jvb6+ThXtJkXeRDZPnb1auM=", - "validators_hash": "X7yBLGyFWnZvyakBElaaaqyV0iCSNTINfm+puFxcX/g=", - "next_validators_hash": "X7yBLGyFWnZvyakBElaaaqyV0iCSNTINfm+puFxcX/g=", - "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", - "app_hash": "pqd8GP5/icLOzlysLtq9IupqfLmoxNVySLWNarJssbE=", - "last_results_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", - "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", - "proposer_address": "oFwwfI48D9wGpICbXtGZNlx6xOI=" - }, - "data": { - "txs": [ - "CpsCCnsKeQoTL2Jsb2IuTXNnUGF5Rm9yQmxvYhJiCi1jb3Ntb3Mxemdwamp4bWZhNm00ZjU5cTJsNjgzOGp1c2RjcmZ4eHc1ajI4ZG0SCF62zWQ6Pw9TGgLBGyIgo5vwRkbYLo3+Xm1IpV8weKHdFYfqkfDyt8a1vfthQQJCAQASWgpOCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA64OVjUldXAMb1uSZqrBNuYaatsk+CMGyQKNzY2vM5T+EgQKAggBEggQgIDpg7HeFhpAM88quyAFPvk6/4fuiolAJf3SmOLNv471av8uir6yHaJPdsusvOUQ6gK+/gwoksZ2Lytk48k3Gf4F+tcJO06ZBxIBBBoESU5EWA==" - ], - "blobs": [ - { - "namespace_id": "XrbNZDo/D1M=", - "data": "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" - } - ], - "square_size": 4, - "hash": "Pu8CIJqgqCFYkaSvfeS5jvb6+ThXtJkXeRDZPnb1auM=" - }, - "evidence": { - "evidence": [] - }, - "last_commit": { - "height": 11, - "block_id": { - "hash": "MfZsPUTgVOBRak+3xnKdwWEr2NQ1v095T4BYaWcdYTs=", - "part_set_header": { - "total": 1, - "hash": "/qyxxHNcuOyYBcaGw90PqAa2GdFErMHkkbH66BDI1hI=" - } - }, - "signatures": [ - { - "block_id_flag": 2, - "validator_address": "oFwwfI48D9wGpICbXtGZNlx6xOI=", - "timestamp": "2023-01-19T01:41:20.109585974Z", - "signature": "mPRPdLbp8cQcZ2w6CmWlmE+4lVzX9YgxzxOBp7lYTT8jYmehJC62sC/Nt/X/ezVW7u9OCXZjGG2oIDYmabKsAA==" - } - ] - } -} \ No newline at end of file From 256f34b1f51bb1efff49aacc0d069a121b4c0ab0 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Thu, 25 May 2023 16:08:52 -0500 Subject: [PATCH 36/39] chore: use local fields Co-authored-by: Rootul P --- api/gateway/share_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index b97de7f290..88c389607d 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -22,8 +22,8 @@ func Test_dataFromShares(t *testing.T) { for _, i := range input { b := coretypes.Blob{ Data: i, - NamespaceID: ns.Bytes()[1:], - NamespaceVersion: namespace.NamespaceVersionZero, + NamespaceID: ns.ID, + NamespaceVersion: ns.Version, ShareVersion: appconsts.ShareVersionZero, } err := sss.Write(b) From 0d841f66dec77e45e24fa98e40d6b2a6dd3e1ae3 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Thu, 25 May 2023 16:09:07 -0500 Subject: [PATCH 37/39] chore: typo Co-authored-by: Rootul P --- core/eds_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/eds_test.go b/core/eds_test.go index b0e2e735a1..01a2f86d58 100644 --- a/core/eds_test.go +++ b/core/eds_test.go @@ -30,7 +30,7 @@ func TestTrulyEmptySquare(t *testing.T) { // transactions or blobs computes the correct data root the minimum DAH. // Technically, this block data is invalid because the construction of the // square is deterministic, and the rules which dictate the square size do not -// allow for empty block data. However, should that ever occur, we need to to +// allow for empty block data. However, should that ever occur, we need to // ensure that the correct data root is generated. func TestNonEmptySquareWithZeroTxs(t *testing.T) { data := types.Data{ From 16780997ed610c7e70fce315c7da91a7d923e1c0 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 26 May 2023 05:56:04 -0500 Subject: [PATCH 38/39] chore: docs Co-authored-by: Rootul P --- core/eds_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/eds_test.go b/core/eds_test.go index 01a2f86d58..6bc04c96c4 100644 --- a/core/eds_test.go +++ b/core/eds_test.go @@ -26,12 +26,12 @@ func TestTrulyEmptySquare(t *testing.T) { assert.Nil(t, eds) } -// TestNonEmptySquareWithZeroTxs tests that a non-empty square with no -// transactions or blobs computes the correct data root the minimum DAH. -// Technically, this block data is invalid because the construction of the -// square is deterministic, and the rules which dictate the square size do not -// allow for empty block data. However, should that ever occur, we need to -// ensure that the correct data root is generated. +// TestNonZeroSquareSize tests that the DAH hash of a block with no transactions +// is equal to the DAH hash for an empty root even if SquareSize is set to +// something non-zero. Technically, this block data is invalid because the +// construction of the square is deterministic, and the rules which dictate the +// square size do not allow for empty block data. However, should that ever +// occur, we need to ensure that the correct data root is generated. func TestNonEmptySquareWithZeroTxs(t *testing.T) { data := types.Data{ Txs: []types.Tx{}, From b57e78e157550b6a7e3bca231544af23d141a438 Mon Sep 17 00:00:00 2001 From: Wondertan Date: Mon, 29 May 2023 10:46:06 +0200 Subject: [PATCH 39/39] fix review comments --- api/gateway/share_test.go | 13 +++++++------ share/eds/byzantine/bad_encoding.go | 4 ++-- share/eds/eds.go | 6 +++--- share/eds/eds_test.go | 2 +- share/get_test.go | 9 ++++----- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/api/gateway/share_test.go b/api/gateway/share_test.go index 88c389607d..0dc8796284 100644 --- a/api/gateway/share_test.go +++ b/api/gateway/share_test.go @@ -3,15 +3,16 @@ package gateway import ( "testing" + "github.com/stretchr/testify/require" + coretypes "github.com/tendermint/tendermint/types" + "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/namespace" "github.com/celestiaorg/celestia-app/pkg/shares" - "github.com/stretchr/testify/require" - coretypes "github.com/tendermint/tendermint/types" ) func Test_dataFromShares(t *testing.T) { - input := [][]byte{ + testData := [][]byte{ []byte("beep"), []byte("beeap"), []byte("BEEEEAHP"), @@ -19,9 +20,9 @@ func Test_dataFromShares(t *testing.T) { ns := namespace.RandomBlobNamespace() sss := shares.NewSparseShareSplitter() - for _, i := range input { + for _, data := range testData { b := coretypes.Blob{ - Data: i, + Data: data, NamespaceID: ns.ID, NamespaceVersion: ns.Version, ShareVersion: appconsts.ShareVersionZero, @@ -41,5 +42,5 @@ func Test_dataFromShares(t *testing.T) { parsedSSSShares, err := dataFromShares(rawSSSShares) require.NoError(t, err) - require.Equal(t, input, parsedSSSShares) + require.Equal(t, testData, parsedSSSShares) } diff --git a/share/eds/byzantine/bad_encoding.go b/share/eds/byzantine/bad_encoding.go index 3f7fab1d80..4e673ed8b8 100644 --- a/share/eds/byzantine/bad_encoding.go +++ b/share/eds/byzantine/bad_encoding.go @@ -5,13 +5,13 @@ import ( "errors" "fmt" - "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/wrapper" "github.com/celestiaorg/go-fraud" libhead "github.com/celestiaorg/go-header" "github.com/celestiaorg/rsmt2d" "github.com/celestiaorg/celestia-node/header" + "github.com/celestiaorg/celestia-node/share" pb "github.com/celestiaorg/celestia-node/share/eds/byzantine/pb" "github.com/celestiaorg/celestia-node/share/ipld" ) @@ -157,7 +157,7 @@ func (p *BadEncodingProof) Validate(hdr libhead.Header) error { } odsWidth := uint64(len(merkleRowRoots) / 2) - codec := appconsts.DefaultCodec() + codec := share.DefaultRSMT2DCodec() // rebuild a row or col. rebuiltShares, err := codec.Decode(shares) diff --git a/share/eds/eds.go b/share/eds/eds.go index 5bd8ad499b..4e96fd684e 100644 --- a/share/eds/eds.go +++ b/share/eds/eds.go @@ -220,12 +220,12 @@ func getQuadrantCells(eds *rsmt2d.ExtendedDataSquare, i, j uint) [][]byte { // prependNamespace adds the namespace to the passed share if in the first quadrant, // otherwise it adds the ParitySharesNamespace to the beginning. func prependNamespace(quadrant int, share []byte) []byte { - r := make([]byte, 0, appconsts.NamespaceSize+appconsts.ShareSize) + namespacedShare := make([]byte, 0, appconsts.NamespaceSize+appconsts.ShareSize) switch quadrant { case 0: - return append(append(r, share[:ipld.NamespaceSize]...), share...) + return append(append(namespacedShare, share[:ipld.NamespaceSize]...), share...) case 1, 2, 3: - return append(append(r, namespace.ParitySharesNamespace.Bytes()...), share...) + return append(append(namespacedShare, namespace.ParitySharesNamespace.Bytes()...), share...) default: panic("invalid quadrant") } diff --git a/share/eds/eds_test.go b/share/eds/eds_test.go index 8859c753b7..8df05d7d53 100644 --- a/share/eds/eds_test.go +++ b/share/eds/eds_test.go @@ -52,7 +52,7 @@ func TestQuadrantOrder(t *testing.T) { shares[i] = rand.Bytes(testShareSize) } - eds, err := rsmt2d.ComputeExtendedDataSquare(shares, appconsts.DefaultCodec(), rsmt2d.NewDefaultTree) + eds, err := rsmt2d.ComputeExtendedDataSquare(shares, share.DefaultRSMT2DCodec(), rsmt2d.NewDefaultTree) require.NoError(t, err) res := quadrantOrder(eds) diff --git a/share/get_test.go b/share/get_test.go index fca1998141..8eafe84cd8 100644 --- a/share/get_test.go +++ b/share/get_test.go @@ -18,7 +18,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/celestiaorg/celestia-app/pkg/appconsts" "github.com/celestiaorg/celestia-app/pkg/wrapper" "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" @@ -76,7 +75,7 @@ func TestBlockRecovery(t *testing.T) { t.Run(tc.name, func(t *testing.T) { squareSize := utils.SquareSize(len(tc.shares)) - eds, err := rsmt2d.ComputeExtendedDataSquare(tc.shares, appconsts.DefaultCodec(), wrapper.NewConstructor(squareSize)) + eds, err := rsmt2d.ComputeExtendedDataSquare(tc.shares, DefaultRSMT2DCodec(), wrapper.NewConstructor(squareSize)) require.NoError(t, err) // calculate roots using the first complete square @@ -89,7 +88,7 @@ func TestBlockRecovery(t *testing.T) { rdata := removeRandShares(flat, tc.d) eds, err = rsmt2d.ImportExtendedDataSquare( rdata, - appconsts.DefaultCodec(), + DefaultRSMT2DCodec(), wrapper.NewConstructor(squareSize), ) require.NoError(t, err) @@ -102,7 +101,7 @@ func TestBlockRecovery(t *testing.T) { } assert.NoError(t, err) - reds, err := rsmt2d.ImportExtendedDataSquare(rdata, appconsts.DefaultCodec(), wrapper.NewConstructor(squareSize)) + reds, err := rsmt2d.ImportExtendedDataSquare(rdata, DefaultRSMT2DCodec(), wrapper.NewConstructor(squareSize)) require.NoError(t, err) // check that the squares are equal assert.Equal(t, ExtractEDS(eds), ExtractEDS(reds)) @@ -117,7 +116,7 @@ func Test_ConvertEDStoShares(t *testing.T) { // compute extended square eds, err := rsmt2d.ComputeExtendedDataSquare( shares, - appconsts.DefaultCodec(), + DefaultRSMT2DCodec(), wrapper.NewConstructor(uint64(squareWidth)), ) require.NoError(t, err)