Skip to content
Cosmopediaby Unity Nodes
Documentationinformalsystems/auditsinformalsystems/audits › CelestiaView on informalsystems/audits ↗

Code review of the payment module

Code review of the payment module

  • code is not well structured, most of the methods are in x/payment/types not really grouped based on functionality

Code quality

Transaction Lifecycle

CheckTx

Note: Although the desired outcome is only for MsgWirePayForData messages to be submitted to the application via CheckTx, there is nothing stopping MsgPayForData messages to be in the mempool.

MessageSource codeBrief descriptionUTsIssues found
MsgWirePayForDataValidateBasicStateless checks of MsgWirePayForData.TestWirePayForData_ValidateBasic- CreateCommitment could be expensive for CheckTx <br /> - WirePayForData with empty Message
MsgPayForDataSee DeliverTx section below

CreateCommitment

func CreateCommitment(k uint64, namespace, message []byte) {
    // ...
    shares := msg.SplitIntoShares().RawShares()
    // SplitIntoShares() => list of shares: (nid|len|partial-message1, nid), (nid|len|partial-message2, nid), ...
    // .RawShares() => [nid|len|partial-message1, nid|len|partial-message2 ... ]
    if uint64(len(shares)) > (k*k)-1 {
		return nil, fmt.Errorf("message size exceeds max shares for square size %d: max %d taken %d", k, (k*k)-1, len(shares))
	}
    // TODO this check assumes that only this message gets in the square (no txs or evidence)

    // split shares into leafSets, each of size k or a power of two < k
    //  - create an ErasuredNamespacedMerkleTree subtree for every set in leafSets
    //      - for every leaf in set, nsLeaf=namespace|leaf is added as a leaf in the subtree
    //      via ErasuredNamespacedMerkleTree.Push(nsLeaf)
    //          - prefix share with another namespace !!!
    //      - compute root of subtree
    //  - compute hash of all the subtree roots 
    return merkle.HashFromByteSlices(subTreeRoots)
}

func (msgs Messages) SplitIntoShares() NamespacedShares {
    shares := make([]NamespacedShare, 0)
    for _, m := range msgs.MessagesList {
        rawData, err := m.MarshalDelimited()
        // rawData: len | data
        shares = AppendToShares(shares, m.NamespaceID, rawData)
    }
    return shares
}

func AppendToShares(shares []NamespacedShare, nid namespace.ID, rawData []byte) []NamespacedShare {
    if len(rawData) <= 248 {
        // rawShare: nid | len | data
        // paddedShare: zeroPadIfNecessary up to 256
        share := NamespacedShare{paddedShare, nid}
        // !!! a share has the nid twice !!!
        shares = append(shares, share)
    } else {
        shares = append(shares, splitMessage(rawData, nid)...)
	}
	return shares
}

// splitMessage breaks the data in a message into the minimum number of
// namespaced shares
func splitMessage(rawData []byte, nid namespace.ID) NamespacedShares {
    // result: (nid|len|partialData1, nid), (nid|len|partialData2, nid), ...
}

PrepareProposal

MethodInvoked byBrief descriptionUTsIssues found
parsedTxs()PrepareProposalParse TXs in proposed block.estimate_square_size_test.go- MsgWirePayForData messages are validate twice by the proposer
estimateSquareSize()PrepareProposalEstimate square size using the data in the proposed block.Test_estimateSquareSize- nextPowerOfTwo vs. NextHigherPowerOf2
rawShareCount()estimateSquareSizeCalculates the number of shares needed by the block data.NA- [Optimization] MsgSharesUsed requires remainder operation <br /> - The number of TX shares is incremented twice <br /> - Unit length missing from estimating txBytes in rawShareCount <br /> - Number of share estimated by rawShareCount is inaccurate
FitsInSquareestimateSquareSizeUses the non interactive default rules to see if messages of some lengths will fit in a square of squareSize starting at share index cursor.TestFitsInSquare- FitsInSquare is incorrect for edge case
prunePrepareProposalRemoves txs until the set of txs will fit in the square.Test_pruning- Inconsistency while pruning compact shares <br> - Redundancy in PrepareProposal
malleateTxsPrepareProposalProcess any MsgWirePayForData transactions into MsgPayForData and their respective messages.NANA
malleatemalleateTxsSplit MsgWirePayForData txs into MsgPayForData txs and data.NA- Complex logic for estimating the square size
ProcessWirePayForDatamalleateParses the MsgWirePayForData to produce the components needed to create a single MsgPayForData.TestProcessMessageNA
calculateCompactShareCountmalleateTxscalculates the exact number of compact shares usedTest_calculateCompactShareCount- ShareIndex offset in calculateCompactShareCount
NewCompactShareSplittercalculateCompactShareCountCreates a CompactShareSplitter.TestCompactShareWriterNA
SplitPrepareProposalconverts block data into encoded sharesNA- SparseShareSplitter writer can be simplified
ExtendSharesPrepareProposalErasure the data square. Relies on the rsmt2d library.TestExtendSharesNA
NewDataAvailabilityHeaderPrepareProposalGenerates a DataAvailability header using the provided square size and shares.TestNewDataAvailabilityHeaderNA

ProcessProposal

MethodInvoked byBrief descriptionUTsIssues found
ProcessProposalABCI++TestMessageInclusionCheck- Minor: Inconsistency re. number of messages in PFDs <br /> - Commitments checked only in ProcessProposal
SplitProcessProposalconverts block data into encoded sharesNASee PrepareProposal
NewDataAvailabilityHeaderProcessProposalGenerates a DataAvailability header using the provided square size and shares.TestNewDataAvailabilityHeaderSee PrepareProposal
GetCommitProcessProposalGet PFD commitmentNANA
calculateCommitPathsGetCommitCalculates all of the paths to subtree roots needed to create the commitment for a given message.Test_calculateSubTreeRootCoordinatesNA
getSubTreeRootGetCommitTraverses the nmt of the selected row and returns the subtree root.TestEDSSubRootCacherNA

DeliverTx

Note: Only MsgPayForData are delivered to the payment module.

MessageSource codeBrief descriptionUTsIssues found
MsgPayForDataValidateBasicStateless checks of MsgPayForData.TestValidateBasic- MsgPayForData.ValidateBasic doesn't invalidate reserved namespaces
MsgPayForDataMsgServer.PayForDataExecute MsgPayForData: Consume msg.MessageSize amount of gas.TestPayForDataGasNone