diff --git a/app/default_overrides.go b/app/default_overrides.go index eb21c62af4..0ceedaeee1 100644 --- a/app/default_overrides.go +++ b/app/default_overrides.go @@ -8,6 +8,7 @@ import ( "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" "github.com/celestiaorg/celestia-app/v3/x/mint" minttypes "github.com/celestiaorg/celestia-app/v3/x/mint/types" + "github.com/celestiaorg/go-square/v2/share" "github.com/cosmos/cosmos-sdk/codec" serverconfig "github.com/cosmos/cosmos-sdk/server/config" sdk "github.com/cosmos/cosmos-sdk/types" @@ -268,7 +269,7 @@ func DefaultConsensusConfig() *tmcfg.Config { // We set a loose upper bound on what we expect the transaction to // be based on the upper bound size of the entire block for the given // version. This acts as a first line of DoS protection - upperBoundBytes := appconsts.DefaultSquareSizeUpperBound * appconsts.DefaultSquareSizeUpperBound * appconsts.ContinuationSparseShareContentSize + upperBoundBytes := appconsts.DefaultSquareSizeUpperBound * appconsts.DefaultSquareSizeUpperBound * share.ContinuationSparseShareContentSize cfg.Mempool.MaxTxBytes = upperBoundBytes cfg.Mempool.MaxTxsBytes = int64(upperBoundBytes) * cfg.Mempool.TTLNumBlocks cfg.Mempool.Version = "v1" // prioritized mempool diff --git a/app/errors/insufficient_gas_price_test.go b/app/errors/insufficient_gas_price_test.go index 049f1afb00..473465ba23 100644 --- a/app/errors/insufficient_gas_price_test.go +++ b/app/errors/insufficient_gas_price_test.go @@ -40,7 +40,7 @@ func TestInsufficientMinGasPriceIntegration(t *testing.T) { signer, err := user.NewSigner(kr, enc.TxConfig, testutil.ChainID, appconsts.LatestVersion, user.NewAccount(account, acc.GetAccountNumber(), acc.GetSequence())) require.NoError(t, err) - b, err := blob.NewBlob(share.RandomNamespace(), []byte("hello world"), 0) + b, err := blob.NewV0Blob(share.RandomNamespace(), []byte("hello world")) require.NoError(t, err) msg, err := blob.NewMsgPayForBlobs(signer.Account(account).Address().String(), appconsts.LatestVersion, b) diff --git a/app/errors/nonce_mismatch_test.go b/app/errors/nonce_mismatch_test.go index 0f8744ae03..a61dacf6a6 100644 --- a/app/errors/nonce_mismatch_test.go +++ b/app/errors/nonce_mismatch_test.go @@ -35,7 +35,7 @@ func TestNonceMismatchIntegration(t *testing.T) { signer, err := user.NewSigner(kr, enc.TxConfig, testutil.ChainID, appconsts.LatestVersion, user.NewAccount(account, acc.GetAccountNumber(), acc.GetSequence()+1)) require.NoError(t, err) - b, err := blob.NewBlob(share.RandomNamespace(), []byte("hello world"), 0) + b, err := blob.NewV0Blob(share.RandomNamespace(), []byte("hello world")) require.NoError(t, err) msg, err := blob.NewMsgPayForBlobs(signer.Account(account).Address().String(), appconsts.LatestVersion, b) diff --git a/app/test/check_tx_test.go b/app/test/check_tx_test.go index 14b7a40f89..45ac426d88 100644 --- a/app/test/check_tx_test.go +++ b/app/test/check_tx_test.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" tmrand "github.com/tendermint/tendermint/libs/rand" "github.com/celestiaorg/celestia-app/v3/app" @@ -14,6 +15,7 @@ import ( "github.com/celestiaorg/celestia-app/v3/pkg/user" testutil "github.com/celestiaorg/celestia-app/v3/test/util" "github.com/celestiaorg/celestia-app/v3/test/util/blobfactory" + "github.com/celestiaorg/celestia-app/v3/test/util/testnode" blobtypes "github.com/celestiaorg/celestia-app/v3/x/blob/types" "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/go-square/v2/tx" @@ -30,7 +32,7 @@ func TestCheckTx(t *testing.T) { ns1, err := share.NewV0Namespace(bytes.Repeat([]byte{1}, share.NamespaceVersionZeroIDSize)) require.NoError(t, err) - accs := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"} + accs := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"} testApp, kr := testutil.SetupTestAppWithGenesisValSet(app.DefaultConsensusParams(), accs...) testApp.Commit() @@ -182,6 +184,32 @@ func TestCheckTx(t *testing.T) { }, expectedABCICode: blobtypes.ErrBlobsTooLarge.ABCICode(), }, + { + name: "v1 blob with invalid signer", + checkType: abci.CheckTxType_New, + getTx: func() []byte { + signer := createSigner(t, kr, accs[10], encCfg.TxConfig, 11) + blob, err := share.NewV1Blob(share.RandomBlobNamespace(), []byte("data"), testnode.RandomAddress().(sdk.AccAddress)) + require.NoError(t, err) + blobTx, _, err := signer.CreatePayForBlobs(accs[10], []*share.Blob{blob}, opts...) + require.NoError(t, err) + return blobTx + }, + expectedABCICode: blobtypes.ErrInvalidBlobSigner.ABCICode(), + }, + { + name: "v1 blob with valid signer", + checkType: abci.CheckTxType_New, + getTx: func() []byte { + signer := createSigner(t, kr, accs[10], encCfg.TxConfig, 11) + blob, err := share.NewV1Blob(share.RandomBlobNamespace(), []byte("data"), signer.Account(accs[10]).Address()) + require.NoError(t, err) + blobTx, _, err := signer.CreatePayForBlobs(accs[10], []*share.Blob{blob}, opts...) + require.NoError(t, err) + return blobTx + }, + expectedABCICode: abci.CodeTypeOK, + }, } for _, tt := range tests { diff --git a/app/test/consistent_apphash_test.go b/app/test/consistent_apphash_test.go index 20fef6cbf5..972f42da58 100644 --- a/app/test/consistent_apphash_test.go +++ b/app/test/consistent_apphash_test.go @@ -381,6 +381,9 @@ func executeTxs(testApp *app.App, encodedBlobTx []byte, encodedSdkTxs [][]byte, // Dynamically increase time so the validator can be unjailed (1m duration) Time: genesisTime.Add(time.Duration(height) * time.Minute), }) + if len(resPrepareProposal.BlockData.Txs) != len(encodedSdkTxs) { + return nil, nil, fmt.Errorf("PrepareProposal removed transactions. Was %d, now %d", len(encodedSdkTxs), len(resPrepareProposal.BlockData.Txs)) + } dataHash := resPrepareProposal.BlockData.Hash diff --git a/app/test/fuzz_abci_test.go b/app/test/fuzz_abci_test.go index 96ec81b7ea..e6bd0127f0 100644 --- a/app/test/fuzz_abci_test.go +++ b/app/test/fuzz_abci_test.go @@ -9,6 +9,7 @@ import ( "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" "github.com/celestiaorg/celestia-app/v3/pkg/user" testutil "github.com/celestiaorg/celestia-app/v3/test/util" + "github.com/celestiaorg/go-square/v2/share" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" tmrand "github.com/tendermint/tendermint/libs/rand" @@ -62,17 +63,17 @@ func TestPrepareProposalConsistency(t *testing.T) { }, { "max", - maxShareCount * appconsts.ContinuationSparseShareContentSize, + maxShareCount * share.ContinuationSparseShareContentSize, appconsts.DefaultSquareSizeUpperBound, }, { "larger MaxBytes than SquareSize", - maxShareCount * appconsts.ContinuationSparseShareContentSize, + maxShareCount * share.ContinuationSparseShareContentSize, appconsts.DefaultGovMaxSquareSize, }, { "smaller MaxBytes than SquareSize", - 32 * 32 * appconsts.ContinuationSparseShareContentSize, + 32 * 32 * share.ContinuationSparseShareContentSize, appconsts.DefaultGovMaxSquareSize, }, } diff --git a/app/test/integration_test.go b/app/test/integration_test.go index 6988843357..aec6d86e46 100644 --- a/app/test/integration_test.go +++ b/app/test/integration_test.go @@ -289,7 +289,7 @@ func (s *IntegrationTestSuite) TestEmptyBlock() { func newBlobWithSize(size int) *share.Blob { ns := share.MustNewV0Namespace(bytes.Repeat([]byte{1}, share.NamespaceVersionZeroIDSize)) data := tmrand.Bytes(size) - blob, err := share.NewBlob(ns, data, appconsts.ShareVersionZero, nil) + blob, err := share.NewBlob(ns, data, share.ShareVersionZero, nil) if err != nil { panic(err) } diff --git a/app/test/process_proposal_test.go b/app/test/process_proposal_test.go index c4492dc602..df390dcdfa 100644 --- a/app/test/process_proposal_test.go +++ b/app/test/process_proposal_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -24,6 +25,8 @@ import ( testutil "github.com/celestiaorg/celestia-app/v3/test/util" "github.com/celestiaorg/celestia-app/v3/test/util/blobfactory" "github.com/celestiaorg/celestia-app/v3/test/util/testfactory" + "github.com/celestiaorg/celestia-app/v3/test/util/testnode" + blobtypes "github.com/celestiaorg/celestia-app/v3/x/blob/types" "github.com/celestiaorg/go-square/v2" "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/go-square/v2/tx" @@ -117,7 +120,7 @@ func TestProcessProposal(t *testing.T) { mutator: func(d *tmproto.Data) { blobTx, _, err := tx.UnmarshalBlobTx(blobTxs[0]) require.NoError(t, err) - newBlob, err := share.NewBlob(ns1, data, appconsts.ShareVersionZero, nil) + newBlob, err := share.NewBlob(ns1, data, share.ShareVersionZero, nil) require.NoError(t, err) blobTx.Blobs[0] = newBlob blobTxBytes, _ := tx.MarshalBlobTx(blobTx.Tx, blobTx.Blobs...) @@ -132,7 +135,7 @@ func TestProcessProposal(t *testing.T) { mutator: func(d *tmproto.Data) { blobTx, _, err := tx.UnmarshalBlobTx(blobTxs[0]) require.NoError(t, err) - newBlob, err := share.NewBlob(share.TxNamespace, data, appconsts.ShareVersionZero, nil) + newBlob, err := share.NewBlob(share.TxNamespace, data, share.ShareVersionZero, nil) require.NoError(t, err) blobTx.Blobs[0] = newBlob blobTxBytes, _ := tx.MarshalBlobTx(blobTx.Tx, blobTx.Blobs...) @@ -259,6 +262,43 @@ func TestProcessProposal(t *testing.T) { appVersion: appconsts.LatestVersion, expectedResult: abci.ResponseProcessProposal_REJECT, }, + { + name: "valid v1 authored blob", + input: validData(), + mutator: func(d *tmproto.Data) { + addr := signer.Account(accounts[0]).Address() + blob, err := share.NewV1Blob(ns1, data, addr) + require.NoError(t, err) + rawTx, _, err := signer.CreatePayForBlobs(accounts[0], []*share.Blob{blob}, user.SetGasLimit(100000), user.SetFee(100000)) + require.NoError(t, err) + d.Txs[0] = rawTx + d.Hash = calculateNewDataHash(t, d.Txs) + }, + appVersion: appconsts.LatestVersion, + expectedResult: abci.ResponseProcessProposal_ACCEPT, + }, + { + name: "v1 authored blob with invalid signer", + input: validData(), + mutator: func(d *tmproto.Data) { + addr := signer.Account(accounts[0]).Address() + falseAddr := testnode.RandomAddress().(sdk.AccAddress) + blob, err := share.NewV1Blob(ns1, data, falseAddr) + require.NoError(t, err) + msg, err := blobtypes.NewMsgPayForBlobs(addr.String(), appconsts.LatestVersion, blob) + require.NoError(t, err) + + rawTx, err := signer.CreateTx([]sdk.Msg{msg}, user.SetGasLimit(100000), user.SetFee(100000)) + require.NoError(t, err) + + blobTxBytes, err := tx.MarshalBlobTx(rawTx, blob) + require.NoError(t, err) + d.Txs[0] = blobTxBytes + d.Hash = calculateNewDataHash(t, d.Txs) + }, + appVersion: appconsts.LatestVersion, + expectedResult: abci.ResponseProcessProposal_REJECT, + }, } for _, tt := range tests { diff --git a/app/test/square_size_test.go b/app/test/square_size_test.go index fa529b519f..e8082b17f5 100644 --- a/app/test/square_size_test.go +++ b/app/test/square_size_test.go @@ -86,7 +86,7 @@ func (s *SquareSizeIntegrationTest) TestSquareSizeUpperBound() { { name: "gov square size == hardcoded max", govMaxSquareSize: appconsts.DefaultSquareSizeUpperBound, - maxBytes: appconsts.DefaultSquareSizeUpperBound * appconsts.DefaultSquareSizeUpperBound * appconsts.ContinuationSparseShareContentSize, + maxBytes: appconsts.DefaultUpperBoundMaxBytes, expectedMaxSquareSize: appconsts.DefaultSquareSizeUpperBound, }, } diff --git a/app/test/std_sdk_test.go b/app/test/std_sdk_test.go index b9d1c03af3..1ef3766e8a 100644 --- a/app/test/std_sdk_test.go +++ b/app/test/std_sdk_test.go @@ -365,7 +365,7 @@ func (s *StandardSDKIntegrationTestSuite) TestGRPCQueries() { txSubmitter, err := user.SetupTxClient(s.cctx.GoContext(), s.cctx.Keyring, s.cctx.GRPCClient, s.ecfg) require.NoError(t, err) - blobs := blobfactory.RandBlobsWithNamespace([]share.Namespace{share.RandomNamespace()}, []int{1000}) + blobs := blobfactory.RandV0BlobsWithNamespace([]share.Namespace{share.RandomNamespace()}, []int{1000}) res, err := txSubmitter.SubmitPayForBlob(s.cctx.GoContext(), blobs, blobfactory.DefaultTxOpts()...) require.NoError(t, err) diff --git a/pkg/appconsts/global_consts.go b/pkg/appconsts/global_consts.go index a7004d0e4d..340f651840 100644 --- a/pkg/appconsts/global_consts.go +++ b/pkg/appconsts/global_consts.go @@ -1,9 +1,7 @@ package appconsts import ( - "math" - - ns "github.com/celestiaorg/go-square/v2/share" + "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/rsmt2d" "github.com/tendermint/tendermint/pkg/consts" ) @@ -13,55 +11,9 @@ import ( // // They can not change throughout the lifetime of a network. const ( - // NamespaceVersionSize is the size of a namespace version in bytes. - NamespaceVersionSize = ns.NamespaceVersionSize - // NamespaceVersionMaxValue is the maximum value a namespace version can be. - // This const must be updated if NamespaceVersionSize is changed. - NamespaceVersionMaxValue = math.MaxUint8 - - // NamespaceIDSize is the size of a namespace ID in bytes. - NamespaceIDSize = ns.NamespaceIDSize - - // NamespaceSize is the size of a namespace (version + ID) in bytes. - NamespaceSize = ns.NamespaceSize - - // ShareSize is the size of a share in bytes. - ShareSize = 512 - - // ShareInfoBytes is the number of bytes reserved for information. The info - // byte contains the share version and a sequence start indicator. - ShareInfoBytes = 1 - - // SequenceLenBytes is the number of bytes reserved for the sequence length - // that is present in the first share of a sequence. - SequenceLenBytes = 4 - - // ShareVersionZero is the first share version format. - ShareVersionZero = uint8(0) - // DefaultShareVersion is the defacto share version. Use this if you are // unsure of which version to use. - DefaultShareVersion = ShareVersionZero - - // CompactShareReservedBytes is the number of bytes reserved for the location of - // the first unit (transaction, ISR) in a compact share. - CompactShareReservedBytes = 4 - - // FirstCompactShareContentSize is the number of bytes usable for data in - // the first compact share of a sequence. - FirstCompactShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes - SequenceLenBytes - CompactShareReservedBytes - - // ContinuationCompactShareContentSize is the number of bytes usable for - // data in a continuation compact share of a sequence. - ContinuationCompactShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes - CompactShareReservedBytes - - // FirstSparseShareContentSize is the number of bytes usable for data in the - // first sparse share of a sequence. - FirstSparseShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes - SequenceLenBytes - - // ContinuationSparseShareContentSize is the number of bytes usable for data - // in a continuation sparse share of a sequence. - ContinuationSparseShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes + DefaultShareVersion = share.ShareVersionZero // MinSquareSize is the smallest original square width. MinSquareSize = 1 @@ -70,9 +22,6 @@ const ( // data square. MinShareCount = MinSquareSize * MinSquareSize - // MaxShareVersion is the maximum value a share version can be. - MaxShareVersion = 127 - // BondDenom defines the native staking denomination BondDenom = "utia" ) @@ -92,7 +41,7 @@ var ( DefaultCodec = rsmt2d.NewLeoRSCodec // SupportedShareVersions is a list of supported share versions. - SupportedShareVersions = []uint8{ShareVersionZero} + SupportedShareVersions = share.SupportedShareVersions ) // HashLength returns the length of a hash in bytes. diff --git a/pkg/appconsts/initial_consts.go b/pkg/appconsts/initial_consts.go index 09e3a164a4..1f97adf951 100644 --- a/pkg/appconsts/initial_consts.go +++ b/pkg/appconsts/initial_consts.go @@ -1,6 +1,10 @@ package appconsts -import "time" +import ( + "time" + + "github.com/celestiaorg/go-square/v2/share" +) // The following defaults correspond to initial parameters of the network that can be changed, not via app versions // but other means such as on-chain governance, or the nodes local config @@ -11,7 +15,7 @@ const ( // DefaultMaxBytes is the default value for the governance modifiable // maximum number of bytes allowed in a valid block. - DefaultMaxBytes = DefaultGovMaxSquareSize * DefaultGovMaxSquareSize * ContinuationSparseShareContentSize + DefaultMaxBytes = DefaultGovMaxSquareSize * DefaultGovMaxSquareSize * share.ContinuationSparseShareContentSize // DefaultGasPerBlobByte is the default gas cost deducted per byte of blob // included in a PayForBlobs txn @@ -27,3 +31,5 @@ const ( // time can be subject to slashing under conditions of misbehavior. DefaultUnbondingTime = 3 * 7 * 24 * time.Hour ) + +var DefaultUpperBoundMaxBytes = DefaultSquareSizeUpperBound * DefaultSquareSizeUpperBound * share.ContinuationSparseShareContentSize diff --git a/pkg/da/data_availability_header_test.go b/pkg/da/data_availability_header_test.go index 7bd38addb5..fa73aeaa5e 100644 --- a/pkg/da/data_availability_header_test.go +++ b/pkg/da/data_availability_header_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" - "github.com/celestiaorg/go-square/v2/share" + sh "github.com/celestiaorg/go-square/v2/share" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -245,7 +245,7 @@ func TestSquareSize(t *testing.T) { // generateShares generates count number of shares with a constant namespace and // share contents. func generateShares(count int) (shares [][]byte) { - ns1 := share.MustNewV0Namespace(bytes.Repeat([]byte{1}, share.NamespaceVersionZeroIDSize)) + ns1 := sh.MustNewV0Namespace(bytes.Repeat([]byte{1}, sh.NamespaceVersionZeroIDSize)) for i := 0; i < count; i++ { share := generateShare(ns1.Bytes()) @@ -256,7 +256,7 @@ func generateShares(count int) (shares [][]byte) { } func generateShare(namespace []byte) (share []byte) { - remainder := bytes.Repeat([]byte{0xFF}, appconsts.ShareSize-len(namespace)) + remainder := bytes.Repeat([]byte{0xFF}, sh.ShareSize-len(namespace)) share = append(share, namespace...) share = append(share, remainder...) return share diff --git a/pkg/inclusion/nmt_caching_test.go b/pkg/inclusion/nmt_caching_test.go index 80bb19d5b6..5e47ecf36f 100644 --- a/pkg/inclusion/nmt_caching_test.go +++ b/pkg/inclusion/nmt_caching_test.go @@ -190,7 +190,7 @@ func chunkSlice(slice [][]byte, chunkSize int) [][][]byte { // namespace. func generateRandNamespacedRawData(count int) (result [][]byte) { for i := 0; i < count; i++ { - rawData := tmrand.Bytes(appconsts.ShareSize) + rawData := tmrand.Bytes(share.ShareSize) namespace := share.RandomBlobNamespace().Bytes() copy(rawData, namespace) result = append(result, rawData) diff --git a/pkg/user/signer.go b/pkg/user/signer.go index 0340e3ad57..4b39c9bd31 100644 --- a/pkg/user/signer.go +++ b/pkg/user/signer.go @@ -92,6 +92,10 @@ func (s *Signer) CreatePayForBlobs(accountName string, blobs []*share.Blob, opts return nil, 0, fmt.Errorf("account %s not found", accountName) } + if err := blobtypes.ValidateBlobs(blobs...); err != nil { + return nil, 0, err + } + msg, err := blobtypes.NewMsgPayForBlobs(acc.address.String(), s.appVersion, blobs...) if err != nil { return nil, 0, err diff --git a/pkg/wrapper/nmt_wrapper.go b/pkg/wrapper/nmt_wrapper.go index 82ad3ad94b..0da772db25 100644 --- a/pkg/wrapper/nmt_wrapper.go +++ b/pkg/wrapper/nmt_wrapper.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" - appns "github.com/celestiaorg/go-square/v2/share" + "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/nmt" "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" @@ -56,7 +56,7 @@ func NewErasuredNamespacedMerkleTree(squareSize uint64, axisIndex uint, options if squareSize == 0 { panic("cannot create a ErasuredNamespacedMerkleTree of squareSize == 0") } - options = append(options, nmt.NamespaceIDSize(appconsts.NamespaceSize)) + options = append(options, nmt.NamespaceIDSize(share.NamespaceSize)) options = append(options, nmt.IgnoreMaxNamespace(true)) tree := nmt.New(appconsts.NewBaseHashFunc(), options...) return ErasuredNamespacedMerkleTree{squareSize: squareSize, options: options, tree: tree, axisIndex: uint64(axisIndex), shareIndex: 0} @@ -94,16 +94,16 @@ func (w *ErasuredNamespacedMerkleTree) Push(data []byte) error { if w.axisIndex+1 > 2*w.squareSize || w.shareIndex+1 > 2*w.squareSize { return fmt.Errorf("pushed past predetermined square size: boundary at %d index at %d %d", 2*w.squareSize, w.axisIndex, w.shareIndex) } - if len(data) < appconsts.NamespaceSize { + if len(data) < share.NamespaceSize { return fmt.Errorf("data is too short to contain namespace ID") } - nidAndData := make([]byte, appconsts.NamespaceSize+len(data)) - copy(nidAndData[appconsts.NamespaceSize:], data) + nidAndData := make([]byte, share.NamespaceSize+len(data)) + copy(nidAndData[share.NamespaceSize:], data) // use the parity namespace if the cell is not in Q0 of the extended data square if w.isQuadrantZero() { - copy(nidAndData[:appconsts.NamespaceSize], data[:appconsts.NamespaceSize]) + copy(nidAndData[:share.NamespaceSize], data[:share.NamespaceSize]) } else { - copy(nidAndData[:appconsts.NamespaceSize], appns.ParitySharesNamespace.Bytes()) + copy(nidAndData[:share.NamespaceSize], share.ParitySharesNamespace.Bytes()) } err := w.tree.Push(nidAndData) if err != nil { diff --git a/pkg/wrapper/nmt_wrapper_test.go b/pkg/wrapper/nmt_wrapper_test.go index ea807fe90f..0686d59e52 100644 --- a/pkg/wrapper/nmt_wrapper_test.go +++ b/pkg/wrapper/nmt_wrapper_test.go @@ -9,7 +9,7 @@ import ( "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" "github.com/celestiaorg/celestia-app/v3/pkg/wrapper" "github.com/celestiaorg/celestia-app/v3/test/util/testfactory" - appns "github.com/celestiaorg/go-square/v2/share" + "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/nmt" nmtnamespace "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" @@ -50,7 +50,7 @@ func TestRootErasuredNamespacedMerkleTree(t *testing.T) { size := 8 data := testfactory.GenerateRandNamespacedRawData(size) nmtErasured := wrapper.NewErasuredNamespacedMerkleTree(uint64(size), 0) - nmtStandard := nmt.New(sha256.New(), nmt.NamespaceIDSize(appns.NamespaceSize), nmt.IgnoreMaxNamespace(true)) + nmtStandard := nmt.New(sha256.New(), nmt.NamespaceIDSize(share.NamespaceSize), nmt.IgnoreMaxNamespace(true)) for _, d := range data { err := nmtErasured.Push(d) @@ -169,9 +169,9 @@ func TestErasuredNamespacedMerkleTree_ProveRange(t *testing.T) { var namespaceID nmtnamespace.ID if i < sqaureSize { - namespaceID = data[i][:appconsts.NamespaceSize] + namespaceID = data[i][:share.NamespaceSize] } else { - namespaceID = appns.ParitySharesNamespace.Bytes() + namespaceID = share.ParitySharesNamespace.Bytes() } verified := proof.VerifyInclusion(appconsts.NewBaseHashFunc(), namespaceID, [][]byte{data[i]}, root) assert.True(t, verified) diff --git a/test/cmd/txsim/cli_test.go b/test/cmd/txsim/cli_test.go index bf637dfb06..3520221af0 100644 --- a/test/cmd/txsim/cli_test.go +++ b/test/cmd/txsim/cli_test.go @@ -62,7 +62,7 @@ func setup(t testing.TB) (keyring.Keyring, string, string) { // set the consensus params to allow for the max square size cparams := testnode.DefaultConsensusParams() - cparams.Block.MaxBytes = int64(appconsts.DefaultSquareSizeUpperBound*appconsts.DefaultSquareSizeUpperBound) * appconsts.ContinuationSparseShareContentSize + cparams.Block.MaxBytes = int64(appconsts.DefaultMaxBytes) cfg := testnode.DefaultConfig(). WithConsensusParams(cparams). diff --git a/test/txsim/blob.go b/test/txsim/blob.go index b03d725d4b..3fcef2fa33 100644 --- a/test/txsim/blob.go +++ b/test/txsim/blob.go @@ -21,9 +21,10 @@ const fundsForGas int = 1e9 // 1000 TIA // BlobSequence defines a pattern whereby a single user repeatedly sends a pay for blob // message roughly every height. The PFB may consist of several blobs type BlobSequence struct { - namespace share.Namespace - sizes Range - blobsPerPFB Range + namespace share.Namespace + sizes Range + blobsPerPFB Range + shareVersions []uint8 account types.AccAddress useFeegrant bool @@ -31,8 +32,9 @@ type BlobSequence struct { func NewBlobSequence(sizes, blobsPerPFB Range) *BlobSequence { return &BlobSequence{ - sizes: sizes, - blobsPerPFB: blobsPerPFB, + sizes: sizes, + blobsPerPFB: blobsPerPFB, + shareVersions: []uint8{share.ShareVersionZero, share.ShareVersionOne}, } } @@ -43,13 +45,24 @@ func (s *BlobSequence) WithNamespace(namespace share.Namespace) *BlobSequence { return s } +// WithShareVersion provides the option of fixing a predefined share version for +// all blobs else it will randomly select a share version for each blob. +func (s *BlobSequence) WithShareVersion(version uint8) *BlobSequence { + if version != share.ShareVersionZero && version != share.ShareVersionOne { + panic(fmt.Sprintf("invalid share version %d", version)) + } + s.shareVersions = []uint8{version} + return s +} + func (s *BlobSequence) Clone(n int) []Sequence { sequenceGroup := make([]Sequence, n) for i := 0; i < n; i++ { sequenceGroup[i] = &BlobSequence{ - namespace: s.namespace, - sizes: s.sizes, - blobsPerPFB: s.blobsPerPFB, + namespace: s.namespace, + sizes: s.sizes, + blobsPerPFB: s.blobsPerPFB, + shareVersions: s.shareVersions, } } return sequenceGroup @@ -83,7 +96,16 @@ func (s *BlobSequence) Next(_ context.Context, _ grpc.ClientConn, rand *rand.Ran sizes[i] = s.sizes.Rand(rand) } // generate the blobs - blobs := blobfactory.RandBlobsWithNamespace(namespaces, sizes) + var blobs []*share.Blob + shareVersion := s.shareVersions[rand.Intn(len(s.shareVersions))] + switch shareVersion { + case share.ShareVersionZero: + blobs = blobfactory.RandV0BlobsWithNamespace(namespaces, sizes) + case share.ShareVersionOne: + blobs = blobfactory.RandV1BlobsWithNamespace(namespaces, sizes, s.account) + default: + return Operation{}, fmt.Errorf("invalid share version: %d", shareVersion) + } // derive the pay for blob message msg, err := blob.NewMsgPayForBlobs(s.account.String(), appconsts.LatestVersion, blobs...) if err != nil { diff --git a/test/util/blobfactory/payforblob_factory.go b/test/util/blobfactory/payforblob_factory.go index 3601ece8ef..1a4aa6d10c 100644 --- a/test/util/blobfactory/payforblob_factory.go +++ b/test/util/blobfactory/payforblob_factory.go @@ -23,7 +23,7 @@ import ( var ( // TestMaxBlobSize is the maximum size of each blob in a blob transaction, for testing purposes - TestMaxBlobSize = appconsts.ShareSize * 2 * appconsts.DefaultSquareSizeUpperBound + TestMaxBlobSize = share.ShareSize * 2 * appconsts.DefaultSquareSizeUpperBound // TestMaxBlobCount is the maximum number of blobs in a blob transaction, for testing purposes TestMaxBlobCount = 5 ) @@ -31,7 +31,7 @@ var ( func RandMsgPayForBlobsWithSigner(rand *tmrand.Rand, signer string, size, blobCount int) (*blobtypes.MsgPayForBlobs, []*share.Blob) { blobs := make([]*share.Blob, blobCount) for i := 0; i < blobCount; i++ { - blob, err := blobtypes.NewBlob(testfactory.RandomBlobNamespaceWithPRG(rand), tmrand.Bytes(size), appconsts.ShareVersionZero) + blob, err := blobtypes.NewV0Blob(testfactory.RandomBlobNamespaceWithPRG(rand), tmrand.Bytes(size)) if err != nil { panic(err) } @@ -45,11 +45,23 @@ func RandMsgPayForBlobsWithSigner(rand *tmrand.Rand, signer string, size, blobCo return msg, blobs } -func RandBlobsWithNamespace(namespaces []share.Namespace, sizes []int) []*share.Blob { +func RandV0BlobsWithNamespace(namespaces []share.Namespace, sizes []int) []*share.Blob { blobs := make([]*share.Blob, len(namespaces)) var err error for i, ns := range namespaces { - blobs[i], err = share.NewBlob(ns, tmrand.Bytes(sizes[i]), appconsts.ShareVersionZero, nil) + blobs[i], err = share.NewV0Blob(ns, tmrand.Bytes(sizes[i])) + if err != nil { + panic(err) + } + } + return blobs +} + +func RandV1BlobsWithNamespace(namespaces []share.Namespace, sizes []int, signer sdk.AccAddress) []*share.Blob { + blobs := make([]*share.Blob, len(namespaces)) + var err error + for i, ns := range namespaces { + blobs[i], err = share.NewV1Blob(ns, tmrand.Bytes(sizes[i]), signer) if err != nil { panic(err) } @@ -58,7 +70,7 @@ func RandBlobsWithNamespace(namespaces []share.Namespace, sizes []int) []*share. } func RandMsgPayForBlobsWithNamespaceAndSigner(signer string, ns share.Namespace, size int) (*blobtypes.MsgPayForBlobs, *share.Blob) { - blob, err := blobtypes.NewBlob(ns, tmrand.Bytes(size), appconsts.ShareVersionZero) + blob, err := blobtypes.NewV0Blob(ns, tmrand.Bytes(size)) if err != nil { panic(err) } @@ -74,7 +86,7 @@ func RandMsgPayForBlobsWithNamespaceAndSigner(signer string, ns share.Namespace, } func RandMsgPayForBlobs(rand *tmrand.Rand, size int) (*blobtypes.MsgPayForBlobs, *share.Blob) { - blob, err := share.NewBlob(testfactory.RandomBlobNamespaceWithPRG(rand), tmrand.Bytes(size), appconsts.ShareVersionZero, nil) + blob, err := share.NewBlob(testfactory.RandomBlobNamespaceWithPRG(rand), tmrand.Bytes(size), share.ShareVersionZero, nil) if err != nil { panic(err) } @@ -202,7 +214,7 @@ func Repeat[T any](s T, count int) []T { func ManyBlobs(rand *tmrand.Rand, namespaces []share.Namespace, sizes []int) []*share.Blob { blobs := make([]*share.Blob, len(namespaces)) for i, ns := range namespaces { - blob, err := share.NewBlob(ns, rand.Bytes(sizes[i]), appconsts.ShareVersionZero, nil) + blob, err := share.NewBlob(ns, rand.Bytes(sizes[i]), share.ShareVersionZero, nil) if err != nil { panic(err) } @@ -216,7 +228,7 @@ func NestedBlobs(t *testing.T, namespaces []share.Namespace, sizes [][]int) [][] counter := 0 for i, set := range sizes { for _, size := range set { - blob, err := blobtypes.NewBlob(namespaces[counter], tmrand.Bytes(size), appconsts.ShareVersionZero) + blob, err := blobtypes.NewV0Blob(namespaces[counter], tmrand.Bytes(size)) require.NoError(t, err) blobs[i] = append(blobs[i], blob) counter++ diff --git a/test/util/malicious/out_of_order_builder.go b/test/util/malicious/out_of_order_builder.go index f12ee03fd8..a501f9c8cf 100644 --- a/test/util/malicious/out_of_order_builder.go +++ b/test/util/malicious/out_of_order_builder.go @@ -89,7 +89,7 @@ func OutOfOrderExport(b *square.Builder) (square.Square, error) { } // write all the regular transactions into compact shares - txWriter := share.NewCompactShareSplitter(share.TxNamespace, appconsts.ShareVersionZero) + txWriter := share.NewCompactShareSplitter(share.TxNamespace, share.ShareVersionZero) for _, tx := range b.Txs { if err := txWriter.WriteTx(tx); err != nil { return nil, fmt.Errorf("writing tx into compact shares: %w", err) @@ -135,7 +135,7 @@ func OutOfOrderExport(b *square.Builder) (square.Square, error) { // write all the pay for blob transactions into compact shares. We need to do this after allocating the blobs to their // appropriate shares as the starting index of each blob needs to be included in the PFB transaction - pfbWriter := share.NewCompactShareSplitter(share.PayForBlobNamespace, appconsts.ShareVersionZero) + pfbWriter := share.NewCompactShareSplitter(share.PayForBlobNamespace, share.ShareVersionZero) for _, iw := range b.Pfbs { iwBytes, err := proto.Marshal(iw) if err != nil { diff --git a/test/util/malicious/tree.go b/test/util/malicious/tree.go index 4a1107e144..0efa14ec08 100644 --- a/test/util/malicious/tree.go +++ b/test/util/malicious/tree.go @@ -6,6 +6,7 @@ import ( "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" "github.com/celestiaorg/celestia-app/v3/pkg/wrapper" "github.com/celestiaorg/go-square/v2" + "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/nmt" "github.com/celestiaorg/nmt/namespace" "github.com/celestiaorg/rsmt2d" @@ -43,10 +44,10 @@ func NewConstructor(squareSize uint64, opts ...nmt.Option) rsmt2d.TreeConstructo // wrapper.ErasuredNamespacedMerkleTree with predefined square size and // nmt.Options. func (c constructor) NewTree(_ rsmt2d.Axis, axisIndex uint) rsmt2d.Tree { - hasher := NewNmtHasher(appconsts.NewBaseHashFunc(), appconsts.NamespaceSize, true) + hasher := NewNmtHasher(appconsts.NewBaseHashFunc(), share.NamespaceSize, true) copts := []nmt.Option{ nmt.CustomHasher(hasher), - nmt.NamespaceIDSize(appconsts.NamespaceSize), + nmt.NamespaceIDSize(share.NamespaceSize), nmt.IgnoreMaxNamespace(true), } copts = append(copts, c.opts...) diff --git a/test/util/test_app.go b/test/util/test_app.go index 2a9acf2bab..8b4a433e9c 100644 --- a/test/util/test_app.go +++ b/test/util/test_app.go @@ -3,6 +3,7 @@ package util import ( "encoding/json" "fmt" + "os" "testing" "time" @@ -89,7 +90,7 @@ func NewTestApp() *app.App { encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...) return app.New( - log.NewNopLogger(), db, nil, + log.NewTMLogger(os.Stdout), db, nil, cast.ToUint(emptyOpts.Get(server.FlagInvCheckPeriod)), encCfg, 0, @@ -138,7 +139,7 @@ func SetupDeterministicGenesisState(testApp *app.App, pubKeys []cryptotypes.PubK Block: &abci.BlockParams{ // Choose some value large enough to not bottleneck the max square // size - MaxBytes: int64(appconsts.DefaultSquareSizeUpperBound*appconsts.DefaultSquareSizeUpperBound) * appconsts.ContinuationSparseShareContentSize, + MaxBytes: int64(appconsts.DefaultUpperBoundMaxBytes), MaxGas: cparams.Block.MaxGas, }, Evidence: &cparams.Evidence, @@ -187,7 +188,7 @@ func NewTestAppWithGenesisSet(cparams *tmproto.ConsensusParams, genAccounts ...s Block: &abci.BlockParams{ // choose some value large enough to not bottleneck the max square // size - MaxBytes: int64(appconsts.DefaultSquareSizeUpperBound*appconsts.DefaultSquareSizeUpperBound) * appconsts.ContinuationSparseShareContentSize, + MaxBytes: int64(appconsts.DefaultUpperBoundMaxBytes), MaxGas: cparams.Block.MaxGas, }, Evidence: &cparams.Evidence, diff --git a/test/util/testfactory/blob.go b/test/util/testfactory/blob.go index 52b452562a..460814f23a 100644 --- a/test/util/testfactory/blob.go +++ b/test/util/testfactory/blob.go @@ -31,7 +31,7 @@ func GenerateRandomlySizedBlobs(count, maxBlobSize int) []*share.Blob { func GenerateBlobsWithNamespace(count int, blobSize int, ns share.Namespace) []*share.Blob { blobs := make([]*share.Blob, count) for i := 0; i < count; i++ { - blob, err := share.NewBlob(ns, tmrand.Bytes(blobSize), appconsts.ShareVersionZero, nil) + blob, err := share.NewBlob(ns, tmrand.Bytes(blobSize), appconsts.DefaultShareVersion, nil) if err != nil { panic(err) } @@ -48,7 +48,7 @@ func GenerateBlobsWithNamespace(count int, blobSize int, ns share.Namespace) []* func GenerateRandomBlob(dataSize int) *share.Blob { ns := share.MustNewV0Namespace(bytes.Repeat([]byte{0x1}, share.NamespaceVersionZeroIDSize)) - blob, err := share.NewBlob(ns, tmrand.Bytes(dataSize), appconsts.ShareVersionZero, nil) + blob, err := share.NewBlob(ns, tmrand.Bytes(dataSize), appconsts.DefaultShareVersion, nil) if err != nil { panic(err) } @@ -58,7 +58,7 @@ func GenerateRandomBlob(dataSize int) *share.Blob { // GenerateRandomBlobOfShareCount returns a blob that spans the given // number of shares func GenerateRandomBlobOfShareCount(count int) *share.Blob { - size := rawBlobSize(appconsts.FirstSparseShareContentSize * count) + size := rawBlobSize(share.FirstSparseShareContentSize * count) return GenerateRandomBlob(size) } diff --git a/test/util/testfactory/common.go b/test/util/testfactory/common.go index f37d4e4439..7e5fe37997 100644 --- a/test/util/testfactory/common.go +++ b/test/util/testfactory/common.go @@ -4,7 +4,6 @@ import ( "bytes" "sort" - "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" "github.com/celestiaorg/go-square/v2/share" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/hd" @@ -35,7 +34,7 @@ func Repeat[T any](s T, count int) []T { // namespace. func GenerateRandNamespacedRawData(count int) (result [][]byte) { for i := 0; i < count; i++ { - rawData := tmrand.Bytes(appconsts.ShareSize) + rawData := tmrand.Bytes(share.ShareSize) namespace := share.RandomBlobNamespace().Bytes() copy(rawData, namespace) result = append(result, rawData) diff --git a/test/util/testnode/config.go b/test/util/testnode/config.go index cbeaf22d2a..947df61fa9 100644 --- a/test/util/testnode/config.go +++ b/test/util/testnode/config.go @@ -153,7 +153,7 @@ func DefaultTendermintConfig() *tmconfig.Config { // Override the mempool's MaxTxBytes to allow the testnode to accept a // transaction that fills the entire square. Any blob transaction larger // than the square size will still fail no matter what. - maxTxBytes := appconsts.DefaultSquareSizeUpperBound * appconsts.DefaultSquareSizeUpperBound * appconsts.ContinuationSparseShareContentSize + maxTxBytes := appconsts.DefaultUpperBoundMaxBytes tmCfg.Mempool.MaxTxBytes = maxTxBytes // Override the MaxBodyBytes to allow the testnode to accept very large diff --git a/test/util/testnode/node_interaction_api.go b/test/util/testnode/node_interaction_api.go index 4a041503e4..3695ee2a99 100644 --- a/test/util/testnode/node_interaction_api.go +++ b/test/util/testnode/node_interaction_api.go @@ -242,7 +242,7 @@ func (c *Context) PostData(account, broadcastMode string, ns share.Namespace, bl return nil, err } - b, err := types.NewBlob(ns, blobData, appconsts.ShareVersionZero) + b, err := types.NewV0Blob(ns, blobData) if err != nil { return nil, err } diff --git a/x/blob/ante/ante_test.go b/x/blob/ante/ante_test.go index c5fefd3d93..e1f16e2b7a 100644 --- a/x/blob/ante/ante_test.go +++ b/x/blob/ante/ante_test.go @@ -5,7 +5,6 @@ import ( "github.com/celestiaorg/celestia-app/v3/app" "github.com/celestiaorg/celestia-app/v3/app/encoding" - "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" ante "github.com/celestiaorg/celestia-app/v3/x/blob/ante" blob "github.com/celestiaorg/celestia-app/v3/x/blob/types" "github.com/celestiaorg/go-square/v2/share" @@ -33,7 +32,7 @@ func TestPFBAnteHandler(t *testing.T) { // 1 share = 512 bytes = 5120 gas BlobSizes: []uint32{uint32(share.AvailableBytesFromSparseShares(1))}, }, - txGas: appconsts.ShareSize * testGasPerBlobByte, + txGas: share.ShareSize * testGasPerBlobByte, gasConsumed: 0, wantErr: false, }, @@ -42,7 +41,7 @@ func TestPFBAnteHandler(t *testing.T) { pfb: &blob.MsgPayForBlobs{ BlobSizes: []uint32{uint32(share.AvailableBytesFromSparseShares(1)), uint32(share.AvailableBytesFromSparseShares(2))}, }, - txGas: 3 * appconsts.ShareSize * testGasPerBlobByte, + txGas: 3 * share.ShareSize * testGasPerBlobByte, gasConsumed: 0, wantErr: false, }, @@ -52,7 +51,7 @@ func TestPFBAnteHandler(t *testing.T) { // 2 share = 1024 bytes = 10240 gas BlobSizes: []uint32{uint32(share.AvailableBytesFromSparseShares(1) + 1)}, }, - txGas: 2*appconsts.ShareSize*testGasPerBlobByte - 1, + txGas: 2*share.ShareSize*testGasPerBlobByte - 1, gasConsumed: 0, wantErr: true, }, @@ -61,7 +60,7 @@ func TestPFBAnteHandler(t *testing.T) { pfb: &blob.MsgPayForBlobs{ BlobSizes: []uint32{uint32(share.AvailableBytesFromSparseShares(1)), uint32(share.AvailableBytesFromSparseShares(2))}, }, - txGas: 3*appconsts.ShareSize*testGasPerBlobByte - 1, + txGas: 3*share.ShareSize*testGasPerBlobByte - 1, gasConsumed: 0, wantErr: true, }, @@ -71,7 +70,7 @@ func TestPFBAnteHandler(t *testing.T) { // 1 share = 512 bytes = 5120 gas BlobSizes: []uint32{uint32(share.AvailableBytesFromSparseShares(1))}, }, - txGas: appconsts.ShareSize*testGasPerBlobByte + 10000 - 1, + txGas: share.ShareSize*testGasPerBlobByte + 10000 - 1, gasConsumed: 10000, wantErr: true, }, diff --git a/x/blob/client/cli/payforblob.go b/x/blob/client/cli/payforblob.go index 1439f92dde..a5263814a8 100644 --- a/x/blob/client/cli/payforblob.go +++ b/x/blob/client/cli/payforblob.go @@ -115,9 +115,16 @@ The blob must be a hex encoded string of non-zero length. return err } + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + signer := clientCtx.FromAddress + // In case of no file input, get the namespaceID and blob from the arguments if path == "" { - blob, err := getBlobFromArguments(args[0], args[1], namespaceVersion, shareVersion) + blob, err := getBlobFromArguments(args[0], args[1], namespaceVersion, shareVersion, signer) if err != nil { return err } @@ -132,7 +139,7 @@ The blob must be a hex encoded string of non-zero length. var blobs []*share.Blob for _, paresdBlob := range paresdBlobs { - blob, err := getBlobFromArguments(paresdBlob.NamespaceID, paresdBlob.Blob, namespaceVersion, shareVersion) + blob, err := getBlobFromArguments(paresdBlob.NamespaceID, paresdBlob.Blob, namespaceVersion, shareVersion, signer) if err != nil { return err } @@ -151,7 +158,7 @@ The blob must be a hex encoded string of non-zero length. return cmd } -func getBlobFromArguments(namespaceIDArg, blobArg string, namespaceVersion, shareVersion uint8) (*share.Blob, error) { +func getBlobFromArguments(namespaceIDArg, blobArg string, namespaceVersion, shareVersion uint8, signer sdk.AccAddress) (*share.Blob, error) { namespaceID, err := hex.DecodeString(strings.TrimPrefix(namespaceIDArg, "0x")) if err != nil { return nil, fmt.Errorf("failed to decode hex namespace ID: %w", err) @@ -166,12 +173,14 @@ func getBlobFromArguments(namespaceIDArg, blobArg string, namespaceVersion, shar return nil, fmt.Errorf("failure to decode hex blob value %s: %s", hexStr, err.Error()) } - blob, err := types.NewBlob(namespace, rawblob, shareVersion) - if err != nil { - return nil, fmt.Errorf("failure to create blob with hex blob value %s: %s", hexStr, err.Error()) + switch shareVersion { + case share.ShareVersionZero: + return types.NewV0Blob(namespace, rawblob) + case share.ShareVersionOne: + return types.NewV1Blob(namespace, rawblob, signer) + default: + return nil, fmt.Errorf("share version %d is not supported", shareVersion) } - - return blob, nil } func getNamespace(namespaceID []byte, namespaceVersion uint8) (share.Namespace, error) { @@ -197,8 +206,6 @@ func broadcastPFB(cmd *cobra.Command, b ...*share.Blob) error { return err } - // TODO: allow the user to override the share version via a new flag - // See https://github.com/celestiaorg/celestia-app/issues/1041 pfbMsg, err := types.NewMsgPayForBlobs(clientCtx.FromAddress.String(), appconsts.LatestVersion, b...) if err != nil { return err diff --git a/x/blob/keeper/gas_test.go b/x/blob/keeper/gas_test.go index 8c3b6c1c8c..8c7bd534ff 100644 --- a/x/blob/keeper/gas_test.go +++ b/x/blob/keeper/gas_test.go @@ -3,8 +3,8 @@ package keeper_test import ( "testing" - "github.com/celestiaorg/celestia-app/v3/pkg/appconsts" "github.com/celestiaorg/celestia-app/v3/x/blob/types" + "github.com/celestiaorg/go-square/v2/share" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -23,27 +23,27 @@ func TestPayForBlobGas(t *testing.T) { { name: "1 byte blob", // occupies 1 share msg: types.MsgPayForBlobs{BlobSizes: []uint32{1}}, - wantGasConsumed: uint64(1*appconsts.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 1 share * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 5156 gas + wantGasConsumed: uint64(1*share.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 1 share * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 5156 gas }, { name: "100 byte blob", // occupies 1 share msg: types.MsgPayForBlobs{BlobSizes: []uint32{100}}, - wantGasConsumed: uint64(1*appconsts.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), + wantGasConsumed: uint64(1*share.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), }, { name: "1024 byte blob", // occupies 3 shares because share prefix (e.g. namespace, info byte) msg: types.MsgPayForBlobs{BlobSizes: []uint32{1024}}, - wantGasConsumed: uint64(3*appconsts.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 3 shares * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 13348 gas + wantGasConsumed: uint64(3*share.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 3 shares * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 13348 gas }, { name: "3 blobs, 1 share each", msg: types.MsgPayForBlobs{BlobSizes: []uint32{1, 1, 1}}, - wantGasConsumed: uint64(3*appconsts.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 3 shares * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 13348 gas + wantGasConsumed: uint64(3*share.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 3 shares * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 13348 gas }, { name: "3 blobs, 6 shares total", msg: types.MsgPayForBlobs{BlobSizes: []uint32{1024, 800, 100}}, - wantGasConsumed: uint64(6*appconsts.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 6 shares * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 25636 gas + wantGasConsumed: uint64(6*share.ShareSize*types.DefaultGasPerBlobByte + paramLookUpCost), // 6 shares * 512 bytes per share * 8 gas per byte + 1060 gas for fetching param = 25636 gas }, } diff --git a/x/blob/keeper/keeper_test.go b/x/blob/keeper/keeper_test.go index b42aea310c..e3da5cb12a 100644 --- a/x/blob/keeper/keeper_test.go +++ b/x/blob/keeper/keeper_test.go @@ -65,7 +65,7 @@ func convertToEventPayForBlobs(message proto.Message) (*types.EventPayForBlobs, } func createMsgPayForBlob(t *testing.T, signer string, namespace share.Namespace, blobData []byte) *types.MsgPayForBlobs { - blob, err := share.NewBlob(namespace, blobData, appconsts.ShareVersionZero, nil) + blob, err := share.NewBlob(namespace, blobData, share.ShareVersionZero, nil) require.NoError(t, err) msg, err := types.NewMsgPayForBlobs(signer, appconsts.LatestVersion, blob) require.NoError(t, err) diff --git a/x/blob/types/blob_tx.go b/x/blob/types/blob_tx.go index fb5e2af058..1f6273f10c 100644 --- a/x/blob/types/blob_tx.go +++ b/x/blob/types/blob_tx.go @@ -7,24 +7,30 @@ import ( "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/go-square/v2/tx" "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto/merkle" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) -// NewBlob creates a new coretypes.Blob from the provided data after performing -// basic stateless checks over it. -func NewBlob(ns share.Namespace, data []byte, shareVersion uint8) (*share.Blob, error) { +// NewV0Blob creates a new V0 Blob from a provided namespace and data. +func NewV0Blob(ns share.Namespace, data []byte) (*share.Blob, error) { // checks that it is a non reserved, valid namespace err := ValidateBlobNamespace(ns) if err != nil { return nil, err } - if len(data) == 0 { - return nil, ErrZeroBlobSize - } + return share.NewV0Blob(ns, data) +} - return share.NewBlob(ns, data, shareVersion, nil) +// NewV1Blob creates a new V1 Blob from the provided namespace, data and the signer +// that will pay for the blob. +func NewV1Blob(ns share.Namespace, data []byte, signer sdk.AccAddress) (*share.Blob, error) { + err := ValidateBlobNamespace(ns) + if err != nil { + return nil, err + } + return share.NewV1Blob(ns, data, signer) } // ValidateBlobTx performs stateless checks on the BlobTx to ensure that the @@ -65,6 +71,20 @@ func ValidateBlobTx(txcfg client.TxEncodingConfig, bTx *tx.BlobTx, subtreeRootTh return err } + signer, err := sdk.AccAddressFromBech32(msgPFB.Signer) + if err != nil { + return err + } + for _, blob := range bTx.Blobs { + // If share version is 1, assert that the signer in the blob + // matches the signer in the msgPFB. + if blob.ShareVersion() == share.ShareVersionOne { + if !bytes.Equal(blob.Signer(), signer) { + return ErrInvalidBlobSigner.Wrapf("blob signer %s does not match msgPFB signer %s", sdk.AccAddress(blob.Signer()).String(), msgPFB.Signer) + } + } + } + // check that the sizes in the blobTx match the sizes in the msgPFB if !equalSlices(sizes, msgPFB.BlobSizes) { return ErrBlobSizeMismatch.Wrapf("actual %v declared %v", sizes, msgPFB.BlobSizes) diff --git a/x/blob/types/blob_tx_test.go b/x/blob/types/blob_tx_test.go index b03a6239a7..1a2d8295dc 100644 --- a/x/blob/types/blob_tx_test.go +++ b/x/blob/types/blob_tx_test.go @@ -22,16 +22,16 @@ import ( tmrand "github.com/tendermint/tendermint/libs/rand" ) -func TestNewBlob(t *testing.T) { +func TestNewV0Blob(t *testing.T) { rawBlob := []byte{1} - validBlob, err := types.NewBlob(share.RandomBlobNamespace(), rawBlob, appconsts.ShareVersionZero) + validBlob, err := types.NewV0Blob(share.RandomBlobNamespace(), rawBlob) require.NoError(t, err) require.Equal(t, validBlob.Data(), rawBlob) - _, err = types.NewBlob(share.TxNamespace, rawBlob, appconsts.ShareVersionZero) + _, err = types.NewV0Blob(share.TxNamespace, rawBlob) require.Error(t, err) - _, err = types.NewBlob(share.RandomBlobNamespace(), []byte{}, appconsts.ShareVersionZero) + _, err = types.NewV0Blob(share.RandomBlobNamespace(), []byte{}) require.Error(t, err) } @@ -78,7 +78,7 @@ func TestValidateBlobTx(t *testing.T) { require.NoError(t, err) originalBlob := btx.Blobs[0] - differentBlob, err := share.NewBlob(share.RandomBlobNamespace(), originalBlob.Data(), originalBlob.ShareVersion(), nil) + differentBlob, err := share.NewBlob(share.RandomBlobNamespace(), originalBlob.Data(), originalBlob.ShareVersion(), originalBlob.Signer()) require.NoError(t, err) btx.Blobs[0] = differentBlob @@ -90,7 +90,7 @@ func TestValidateBlobTx(t *testing.T) { name: "invalid transaction, no pfb", getTx: func() *tx.BlobTx { sendTx := blobfactory.GenerateManyRawSendTxs(signer, 1) - b, err := types.NewBlob(share.RandomBlobNamespace(), tmrand.Bytes(100), appconsts.ShareVersionZero) + b, err := types.NewV0Blob(share.RandomBlobNamespace(), tmrand.Bytes(100)) require.NoError(t, err) return &tx.BlobTx{ Tx: sendTx[0], @@ -105,7 +105,7 @@ func TestValidateBlobTx(t *testing.T) { rawBtx := validRawBtx() btx, _, err := tx.UnmarshalBlobTx(rawBtx) require.NoError(t, err) - blob, err := types.NewBlob(share.RandomBlobNamespace(), tmrand.Bytes(100), appconsts.ShareVersionZero) + blob, err := types.NewV0Blob(share.RandomBlobNamespace(), tmrand.Bytes(100)) require.NoError(t, err) btx.Blobs = append(btx.Blobs, blob) return btx @@ -115,7 +115,7 @@ func TestValidateBlobTx(t *testing.T) { { name: "invalid share commitment", getTx: func() *tx.BlobTx { - b, err := types.NewBlob(share.RandomBlobNamespace(), tmrand.Bytes(100), appconsts.ShareVersionZero) + b, err := types.NewV0Blob(share.RandomBlobNamespace(), tmrand.Bytes(100)) require.NoError(t, err) msg, err := types.NewMsgPayForBlobs( addr.String(), @@ -124,7 +124,7 @@ func TestValidateBlobTx(t *testing.T) { ) require.NoError(t, err) - anotherBlob, err := share.NewBlob(share.RandomBlobNamespace(), tmrand.Bytes(99), appconsts.ShareVersionZero, nil) + anotherBlob, err := share.NewV0Blob(share.RandomBlobNamespace(), tmrand.Bytes(99)) require.NoError(t, err) badCommit, err := inclusion.CreateCommitment( anotherBlob, @@ -177,7 +177,7 @@ func TestValidateBlobTx(t *testing.T) { name: "normal transaction with two blobs w/ different namespaces", getTx: func() *tx.BlobTx { rawBtx, _, err := signer.CreatePayForBlobs(acc.Name(), - blobfactory.RandBlobsWithNamespace( + blobfactory.RandV0BlobsWithNamespace( []share.Namespace{share.RandomBlobNamespace(), share.RandomBlobNamespace()}, []int{100, 100})) require.NoError(t, err) @@ -192,9 +192,10 @@ func TestValidateBlobTx(t *testing.T) { name: "normal transaction with two large blobs w/ different namespaces", getTx: func() *tx.BlobTx { rawBtx, _, err := signer.CreatePayForBlobs(acc.Name(), - blobfactory.RandBlobsWithNamespace( + blobfactory.RandV0BlobsWithNamespace( []share.Namespace{share.RandomBlobNamespace(), share.RandomBlobNamespace()}, - []int{100000, 1000000}), + []int{100000, 1000000}, + ), ) require.NoError(t, err) btx, isBlobTx, err := tx.UnmarshalBlobTx(rawBtx) @@ -209,9 +210,10 @@ func TestValidateBlobTx(t *testing.T) { getTx: func() *tx.BlobTx { ns := share.RandomBlobNamespace() rawBtx, _, err := signer.CreatePayForBlobs(acc.Name(), - blobfactory.RandBlobsWithNamespace( + blobfactory.RandV0BlobsWithNamespace( []share.Namespace{ns, ns}, - []int{100, 100}), + []int{100, 100}, + ), ) require.NoError(t, err) btx, isBlobTx, err := tx.UnmarshalBlobTx(rawBtx) @@ -233,7 +235,7 @@ func TestValidateBlobTx(t *testing.T) { namespaces[i] = ns } rawBtx, _, err := signer.CreatePayForBlobs(acc.Name(), - blobfactory.RandBlobsWithNamespace( + blobfactory.RandV0BlobsWithNamespace( namespaces, sizes, )) diff --git a/x/blob/types/errors.go b/x/blob/types/errors.go index fd97105532..92735e0578 100644 --- a/x/blob/types/errors.go +++ b/x/blob/types/errors.go @@ -36,4 +36,5 @@ var ( // ErrTotalBlobSize is deprecated, use ErrBlobsTooLarge instead. ErrTotalBlobSizeTooLarge = errors.Register(ModuleName, 11138, "total blob size too large") ErrBlobsTooLarge = errors.Register(ModuleName, 11139, "blob(s) too large") + ErrInvalidBlobSigner = errors.Register(ModuleName, 11140, "invalid blob signer") ) diff --git a/x/blob/types/payforblob.go b/x/blob/types/payforblob.go index c8abc43745..92eca0a4d7 100644 --- a/x/blob/types/payforblob.go +++ b/x/blob/types/payforblob.go @@ -119,7 +119,7 @@ func (msg *MsgPayForBlobs) ValidateBasic() error { } for _, v := range msg.ShareVersions { - if v != uint32(appconsts.ShareVersionZero) { + if v != uint32(share.ShareVersionZero) && v != uint32(share.ShareVersionOne) { return ErrUnsupportedShareVersion } } @@ -151,7 +151,7 @@ func GasToConsume(blobSizes []uint32, gasPerByte uint32) uint64 { totalSharesUsed += uint64(share.SparseSharesNeeded(size)) } - return totalSharesUsed * appconsts.ShareSize * uint64(gasPerByte) + return totalSharesUsed * share.ShareSize * uint64(gasPerByte) } // EstimateGas estimates the total gas required to pay for a set of blobs in a PFB. @@ -198,24 +198,21 @@ func (msg *MsgPayForBlobs) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{address} } -// ValidateBlobs performs basic checks over the components of one or more PFBs. +// ValidateBlobs performs checks that each blob is non-empty and has a valid namespace. +// Other checks are done in the construction of the Blob. func ValidateBlobs(blobs ...*share.Blob) error { if len(blobs) == 0 { return ErrNoBlobs } for _, blob := range blobs { - err := ValidateBlobNamespace(blob.Namespace()) - if err != nil { - return err - } - if blob.IsEmpty() { return ErrZeroBlobSize } - if !slices.Contains(appconsts.SupportedShareVersions, blob.ShareVersion()) { - return ErrUnsupportedShareVersion + err := ValidateBlobNamespace(blob.Namespace()) + if err != nil { + return err } } diff --git a/x/blob/types/payforblob_test.go b/x/blob/types/payforblob_test.go index 0e63b3c721..86d8a544f1 100644 --- a/x/blob/types/payforblob_test.go +++ b/x/blob/types/payforblob_test.go @@ -171,7 +171,7 @@ func validMsgPayForBlobs(t *testing.T) *types.MsgPayForBlobs { ns1 := share.NamespaceVersionZeroPrefix ns1 = append(ns1, bytes.Repeat([]byte{0x01}, share.NamespaceVersionZeroIDSize)...) ns := share.MustNewNamespace(share.NamespaceVersionZero, ns1) - data := bytes.Repeat([]byte{2}, totalBlobSize(appconsts.ContinuationSparseShareContentSize*12)) + data := bytes.Repeat([]byte{2}, totalBlobSize(share.ContinuationSparseShareContentSize*12)) blob, err := share.NewV0Blob(ns, data) require.NoError(t, err) @@ -192,24 +192,33 @@ func TestNewMsgPayForBlobs(t *testing.T) { } ns1 := share.MustNewV0Namespace(bytes.Repeat([]byte{1}, share.NamespaceVersionZeroIDSize)) ns2 := share.MustNewV0Namespace(bytes.Repeat([]byte{2}, share.NamespaceVersionZeroIDSize)) + address := sdk.MustAccAddressFromBech32(testfactory.TestAccAddr) testCases := []testCase{ { name: "valid msg PFB with small blob", signer: testfactory.TestAccAddr, - blobs: []*share.Blob{mustNewBlob(t, ns1, []byte{1}, appconsts.ShareVersionZero, nil)}, + blobs: []*share.Blob{mustNewBlob(t, ns1, []byte{1}, share.ShareVersionZero, nil)}, }, { name: "valid msg PFB with large blob", signer: testfactory.TestAccAddr, - blobs: []*share.Blob{mustNewBlob(t, ns1, tmrand.Bytes(1000000), appconsts.ShareVersionZero, nil)}, + blobs: []*share.Blob{mustNewBlob(t, ns1, tmrand.Bytes(1000000), share.ShareVersionZero, nil)}, }, { name: "valid msg PFB with two blobs", signer: testfactory.TestAccAddr, blobs: []*share.Blob{ - mustNewBlob(t, ns1, []byte{1}, appconsts.ShareVersionZero, nil), - mustNewBlob(t, ns2, []byte{2}, appconsts.ShareVersionZero, nil), + mustNewBlob(t, ns1, []byte{1}, share.ShareVersionZero, nil), + mustNewBlob(t, ns2, []byte{2}, share.ShareVersionZero, nil), + }, + expectedErr: false, + }, + { + name: "valid msg PFB with share version 1", + signer: testfactory.TestAccAddr, + blobs: []*share.Blob{ + mustNewBlob(t, ns1, tmrand.Bytes(10000), share.ShareVersionOne, address), }, expectedErr: false, }, @@ -217,7 +226,7 @@ func TestNewMsgPayForBlobs(t *testing.T) { name: "msg PFB with tx namespace returns an error", signer: testfactory.TestAccAddr, blobs: []*share.Blob{ - mustNewBlob(t, share.TxNamespace, tmrand.Bytes(1000000), appconsts.ShareVersionZero, nil), + mustNewBlob(t, share.TxNamespace, tmrand.Bytes(1000000), share.ShareVersionZero, nil), }, expectedErr: true, }, @@ -225,7 +234,7 @@ func TestNewMsgPayForBlobs(t *testing.T) { name: "msg PFB with invalid signer returns an error", signer: testfactory.TestAccAddr[:10], blobs: []*share.Blob{ - mustNewBlob(t, ns1, []byte{1}, appconsts.ShareVersionZero, nil), + mustNewBlob(t, ns1, []byte{1}, share.ShareVersionZero, nil), }, expectedErr: true, },