From 39d3027b36311db7011ca0847a42e9c49d3e660b Mon Sep 17 00:00:00 2001 From: Rootul P Date: Fri, 4 Nov 2022 03:20:15 -0600 Subject: [PATCH] Update docs for payment module (#948) ## TODO - [x] Split out changes that are only relevant post ADR 008 implementation and target feature branch - [x] Document gas cost for a message - [x] [Potentially] remove outdated code blocks from README.md ## Future PRs - [ ] Params section needs to be updated after params are added to payment module https://github.com/celestiaorg/celestia-app/pull/893 - [ ] [Potentially] add client section (motivated by https://github.com/cosmos/cosmos-sdk/tree/main/x/auth#client) --- x/payment/client/cli/query.go | 11 ++-- x/payment/client/cli/tx.go | 6 +-- x/payment/doc.go | 4 ++ x/payment/keeper/keeper.go | 4 +- x/payment/module.go | 6 +-- x/payment/payfordata.go | 6 +-- x/payment/spec/docs.md | 97 +++++------------------------------ x/payment/types/events.go | 2 +- 8 files changed, 31 insertions(+), 105 deletions(-) create mode 100644 x/payment/doc.go diff --git a/x/payment/client/cli/query.go b/x/payment/client/cli/query.go index ba85b00b6d..93113b2d6e 100644 --- a/x/payment/client/cli/query.go +++ b/x/payment/client/cli/query.go @@ -2,18 +2,13 @@ package cli import ( "fmt" - // "strings" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - // "github.com/cosmos/cosmos-sdk/client/flags" - // sdk "github.com/cosmos/cosmos-sdk/types" "github.com/celestiaorg/celestia-app/x/payment/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" ) -// GetQueryCmd returns the cli query commands for this module +// GetQueryCmd returns the CLI query commands for this module func GetQueryCmd(queryRoute string) *cobra.Command { // Group payment queries under a subcommand cmd := &cobra.Command{ diff --git a/x/payment/client/cli/tx.go b/x/payment/client/cli/tx.go index 60f7957243..39bb45cda6 100644 --- a/x/payment/client/cli/tx.go +++ b/x/payment/client/cli/tx.go @@ -4,11 +4,9 @@ import ( "fmt" "time" - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - // "github.com/cosmos/cosmos-sdk/client/flags" "github.com/celestiaorg/celestia-app/x/payment/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" ) var DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) diff --git a/x/payment/doc.go b/x/payment/doc.go new file mode 100644 index 0000000000..ddabc100f0 --- /dev/null +++ b/x/payment/doc.go @@ -0,0 +1,4 @@ +// payment is a Cosmos SDK module that enables users to pay for data to be +// published to the Celestia blockchain. Please see ./specs/docs.md for the full +// specification of this module. +package payment diff --git a/x/payment/keeper/keeper.go b/x/payment/keeper/keeper.go index 79978c361a..4967f59d9c 100644 --- a/x/payment/keeper/keeper.go +++ b/x/payment/keeper/keeper.go @@ -13,7 +13,7 @@ import ( const payForDataGasDescriptor = "pay for data" -// Keeper handles all the state changes for the celestia-app module. +// Keeper handles all the state changes for the payment module. type Keeper struct { cdc codec.BinaryCodec } @@ -28,7 +28,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -// MsgPayForData moves a user's coins to the module address and burns them. +// PayForData consumes gas based on the message size. func (k Keeper) PayForData(goCtx context.Context, msg *types.MsgPayForData) (*types.MsgPayForDataResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/x/payment/module.go b/x/payment/module.go index 85bf3050e7..e244bcab61 100644 --- a/x/payment/module.go +++ b/x/payment/module.go @@ -133,8 +133,8 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // RegisterInvariants registers the capability module's invariants. func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// InitGenesis performs the capability module's genesis initialization It returns -// no validator updates. +// InitGenesis performs the capability module's genesis initialization. It +// returns an empty list of validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { var genState types.GenesisState // Initialize global index to index in genesis state @@ -158,7 +158,7 @@ func (AppModule) ConsensusVersion() uint64 { return 2 } func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} // EndBlock executes all ABCI EndBlock logic respective to the capability module. It -// returns no validator updates. +// returns an empty list of validator updates. func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } diff --git a/x/payment/payfordata.go b/x/payment/payfordata.go index d11c88d125..54333f31f4 100644 --- a/x/payment/payfordata.go +++ b/x/payment/payfordata.go @@ -13,8 +13,8 @@ import ( "github.com/celestiaorg/nmt/namespace" ) -// SubmitPayForData constructs, signs and synchronously submits a PayForData -// transaction, returning a sdk.TxResponse upon submission. +// SubmitPayForData builds, signs, and synchronously submits a PayForData +// transaction. It returns a sdk.TxResponse after submission. func SubmitPayForData( ctx context.Context, signer *types.KeyringSigner, @@ -48,7 +48,7 @@ func SubmitPayForData( return txResp.TxResponse, nil } -// BuildPayForData constructs a PayForData transaction. +// BuildPayForData builds a PayForData transaction. func BuildPayForData( ctx context.Context, signer *types.KeyringSigner, diff --git a/x/payment/spec/docs.md b/x/payment/spec/docs.md index d4dc9a9da1..58ca981cf9 100644 --- a/x/payment/spec/docs.md +++ b/x/payment/spec/docs.md @@ -1,4 +1,6 @@ -# Abstract +# `x/payment` + +## Abstract The payment module is responsible for paying for arbitrary data that will be added to the Celestia blockchain. While the data being submitted can be arbitrary, the exact placement of that data is important for the transaction to be valid. This is why the payment module utilizes a malleated transaction scheme. Malleated transactions allow for users to create a single transaction, that can later be malleated by the block producer to create a variety of different valid transactions that are still signed over by the user. To accomplish this, users create a single `MsgWirePayForData` transaction, which is composed of metadata and signatures for multiple variations of the transaction that will be included onchain. After the transaction is submitted to the network, the block producer selects the appropriate signature and creates a valid `MsgPayForData` transaction depending on the square size for that block. This new malleated `MsgPayForData` transaction is what ends up onchain. @@ -6,96 +8,22 @@ Further reading: [Message Block Layout](https://github.com/celestiaorg/celestia- ## State -- The sender’s account balance, via the bank keeper’s [`Burn`](https://github.com/cosmos/cosmos-sdk/blob/531bf5084516425e8e3d24bae637601b4d36a191/x/bank/spec/01_state.md) method. -- The standard incrememnt of the sender's account number via the [auth module](https://github.com/cosmos/cosmos-sdk/blob/531bf5084516425e8e3d24bae637601b4d36a191/x/auth/spec/02_state.md). - -## Messages - -- [`MsgWirePayForData`](https://github.com/celestiaorg/celestia-app/blob/b4c8ebdf35db200a9b99d295a13de01110802af4/x/payment/types/tx.pb.go#L32-L40) +The payment module doesn't maintain it's own state. -While this transaction is created and signed by the user, it never actually ends up onchain. Instead, it is used to create a new "malleated" transaction that does get included onchain. +When a PayForData message is processed, it consumes gas based on the message size. -- [`MsgPayForData`](https://github.com/celestiaorg/celestia-app/blob/b4c8ebdf35db200a9b99d295a13de01110802af4/x/payment/types/tx.pb.go#L208-L216) +## Messages -The malleated transaction that is created from metadata contained in the original `MsgWirePayForData`. It also burns some of the sender’s funds. +- [`MsgWirePayForData`](https://github.com/celestiaorg/celestia-app/blob/29e0a2751182499f7dc03598eabfc8d049ae62cb/x/payment/types/tx.pb.go#L32-L40) is a message that is created and signed by the user but it never ends up on-chain. +- [`MsgPayForData`](https://github.com/celestiaorg/celestia-app/blob/29e0a2751182499f7dc03598eabfc8d049ae62cb/x/payment/types/tx.pb.go#L209-L219) is a "malleated" transaction that is created from metadata in the original `MsgWirePayForData`. `MsgPayForData` does end up on-chain. ## PrepareProposal The malleation process occurs during the PrepareProposal step. -```go -// ProcessWirePayForData will perform the processing required by PrepareProposal. -// It parses the MsgWirePayForData to produce the components needed to create a -// single MsgPayForData -func ProcessWirePayForData(msg *MsgWirePayForData, squareSize uint64) (*tmproto.Message, *MsgPayForData, []byte, error) { - // make sure that a ShareCommitAndSignature of the correct size is - // included in the message - var shareCommit *ShareCommitAndSignature - for _, commit := range msg.MessageShareCommitment { - if commit.K == squareSize { - shareCommit = &commit - } - } - if shareCommit == nil { - return nil, - nil, - nil, - fmt.Errorf("message does not commit to current square size: %d", squareSize) - } - - // add the message to the list of core message to be returned to ll-core - coreMsg := tmproto.Message{ - NamespaceId: msg.GetMessageNamespaceId(), - Data: msg.GetMessage(), - } - - // wrap the signed transaction data - pfd, err := msg.unsignedPayForData(squareSize) - if err != nil { - return nil, nil, nil, err - } - - return &coreMsg, pfd, shareCommit.Signature, nil -} - -// PrepareProposal fullfills the celestia-core version of the ACBI interface by -// preparing the proposal block data. The square size is determined by first -// estimating it via the size of the passed block data. Then the included -// MsgWirePayForData messages are malleated into MsgPayForData messages by -// separating the message and transaction that pays for that message. Lastly, -// this method generates the data root for the proposal block and passes it the -// blockdata. -func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - squareSize := app.estimateSquareSize(req.BlockData) - - dataSquare, data := SplitShares(app.txConfig, squareSize, req.BlockData) - - eds, err := da.ExtendShares(squareSize, dataSquare) - if err != nil { - app.Logger().Error( - "failure to erasure the data square while creating a proposal block", - "error", - err.Error(), - ) - panic(err) - } - - dah := da.NewDataAvailabilityHeader(eds) - data.Hash = dah.Hash() - data.OriginalSquareSize = squareSize - - return abci.ResponsePrepareProposal{ - BlockData: data, - } -} -``` - - - ## Events -- [`NewPayForDataEvent`](https://github.com/celestiaorg/celestia-app/pull/213/files#diff-1ce55bda42cf160deca2e5ea1f4382b65f3b689c7e00c88085d7ce219e77303dR17-R21) - Emit an event that has the signer's address and size of the message that is paid for. +- [`NewPayForDataEvent`](https://github.com/celestiaorg/celestia-app/pull/213/files#diff-1ce55bda42cf160deca2e5ea1f4382b65f3b689c7e00c88085d7ce219e77303dR17-R21) is emitted with the signer's address and size of the message that is paid for. ## Parameters @@ -103,15 +31,16 @@ There are no parameters yet, but we might add - BaseFee - SquareSize -- ShareSize ### Usage -`celestia-app tx payment payForData [flags]` +```shell +celestia-app tx payment payForData [flags] +``` ### Programmatic Usage -There are tools to programmatically create, sign, and broadcast `MsgWirePayForDatas` +There are tools to programmatically create, sign, and broadcast `MsgWirePayForData`s ```go // create the raw WirePayForData transaction diff --git a/x/payment/types/events.go b/x/payment/types/events.go index 3d2b991753..7b8b15b45c 100644 --- a/x/payment/types/events.go +++ b/x/payment/types/events.go @@ -13,7 +13,7 @@ const ( AttributeKeySize = "size" ) -// NewPayForDataEvent constructs a new payformessge sdk.Event +// NewPayForDataEvent constructs a new payfordata sdk.Event func NewPayForDataEvent(signer string, size uint64) sdk.Event { return sdk.NewEvent( EventTypePayForData,