From 889e564ff7b9c7ce53e16f72eee344510c649014 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Mon, 29 Aug 2022 23:40:29 -0500 Subject: [PATCH 01/35] init --- .../ADR-003-Non-interactive-defaults.md | 49 ++++++++++++++++++ docs/architecture/assets/after.png | Bin 0 -> 14119 bytes docs/architecture/assets/before.png | Bin 0 -> 11650 bytes .../assets/example-full-block.png | Bin 0 -> 45795 bytes docs/architecture/assets/extra.drawio.png | Bin 0 -> 49992 bytes .../assets/fit-by-removing-tx.drawio.png | Bin 0 -> 35413 bytes .../assets/increased-ns-4.drawio.png | Bin 0 -> 46642 bytes docs/architecture/assets/multi-row-str.png | Bin 0 -> 38126 bytes docs/architecture/assets/subtree-root.png | Bin 0 -> 13749 bytes .../subtreeroot-bold-labeled.drawio.png | Bin 0 -> 10889 bytes .../assets/subtreeroot.drawio.png | Bin 0 -> 9799 bytes 11 files changed, 49 insertions(+) create mode 100644 docs/architecture/ADR-003-Non-interactive-defaults.md create mode 100644 docs/architecture/assets/after.png create mode 100644 docs/architecture/assets/before.png create mode 100644 docs/architecture/assets/example-full-block.png create mode 100644 docs/architecture/assets/extra.drawio.png create mode 100644 docs/architecture/assets/fit-by-removing-tx.drawio.png create mode 100644 docs/architecture/assets/increased-ns-4.drawio.png create mode 100644 docs/architecture/assets/multi-row-str.png create mode 100644 docs/architecture/assets/subtree-root.png create mode 100644 docs/architecture/assets/subtreeroot-bold-labeled.drawio.png create mode 100644 docs/architecture/assets/subtreeroot.drawio.png diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md new file mode 100644 index 0000000000..2e93ac55c8 --- /dev/null +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -0,0 +1,49 @@ +# ADR 003: Non-interactive Defaults, Wrapped Transactions, and Subtree Root Message Inclusion Checks + +## Intro + +Currently, when checking for message inclusion, validators recreate the share commitment from the messages in the block and compare those with what are signed over in the `MsgPayForData` transactions also in that block. If any commitment is not found in one of the PFD transactions, or if there is a commitment that doesn't have a corresponding message, then they reject that block. + +While this functions as a message inclusion check, the light client has to assume that 2/3's of the voting power is honest in order to be assured that both the messages they are interested in and the rest of the messages paid for in that block are actually included. + +To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional message layout rules that allow for commitments to messages to consist entirely of sub tree roots of the data root, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: MODIFIED FROM THE SPEC + + +- Messages begin at a location aligned with the largest power of 2 that is not larger than the message length or k. +- If the largest power of 2 of a given message spans multiple rows it must begin at the start of a row (this can occur if a message is longer than k shares or if the block producer decides to start a message partway through a row and it cannot fit). + +We can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. Below illustrates how we can break a message up into two different subtree roots, the first for first four shares, the second consisting of the last two shares. + +![before](./assets/subtree-root.png "Subtree Root based commitments") + +In practice this means that we end up adding padding between messages (zig-zag hatched share). Padding consists of a the namespace of the message before it, with all zeros for data. + +![before](./assets/before.png "before") +![after](./assets/after.png "after") +![example](./assets/example-full-block.png "example") + + +Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. + + +## Alternative Approaches + +Arranging the messages in the block to maximize for fees is an NP-hard problem because each change to the square potentially affects the rest of the messages in the square. There will likely be many different strategies we could use to quickly and efficiently fill the square in a valid way. + +## Decision + +## Detailed Design + +## Status + +{Deprecated|Proposed|Accepted|Declined} + +## Consequences + +### Positive + +### Negative + +### Neutral + +## References diff --git a/docs/architecture/assets/after.png b/docs/architecture/assets/after.png new file mode 100644 index 0000000000000000000000000000000000000000..841d9a2944906902170e8afdcb7de171fac3b054 GIT binary patch literal 14119 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 literal 0 HcmV?d00001 diff --git a/docs/architecture/assets/before.png b/docs/architecture/assets/before.png new file mode 100644 index 0000000000000000000000000000000000000000..b47834544825f765b5bcc5e57feb074ae7d977c4 GIT binary patch literal 11650 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 kwo#cEw3y+h6nF0{ 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 literal 0 HcmV?d00001 diff --git a/docs/architecture/assets/extra.drawio.png b/docs/architecture/assets/extra.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..beb01a16bfa3bde0587eb67195cfe333e8fc81f2 GIT binary patch literal 49992 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%0App= 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 literal 0 HcmV?d00001 diff --git a/docs/architecture/assets/fit-by-removing-tx.drawio.png b/docs/architecture/assets/fit-by-removing-tx.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..e667947e752d95d159eacb8ae0d7167302214874 GIT binary patch literal 35413 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�@NfBIKp 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 RDN+G{M*3!Y?{%D_{|D1`nVA3p literal 0 HcmV?d00001 diff --git a/docs/architecture/assets/multi-row-str.png b/docs/architecture/assets/multi-row-str.png new file mode 100644 index 0000000000000000000000000000000000000000..74dfb2f88864466e04b84073c2888936c413e6bb GIT binary patch literal 38126 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 AZtd9k|VZlnx9U!ikR2 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%0DHT(BVcq?n@|E>-2oU z032pPwRj_%X=bn8|B(zEJn2oAXU6sj#RbsC=bB@+dGIHyb%&ET0vvz+$OPw>%dg%u_}^kN7Jh{%n$9B!tmZ+C4leCyT>oJF8)zIzrT6F zaZBDn+MtYrjMeZt_OUSqz-O7r*0hf-9jA`?-2&$Brs+DxQ^T94tU1(&Y)d0a)bXjV zZY7!g!bSDKkw6Q93*d!QnS;wShJ65JF1Huq2V$0esS-9-0=WWWorMDINtN7($Pvq|fD@3q$(pVj0^1~0_+ zt#&GktlxSgj~NMCd3V(41-^ZYaoycoTe|HzBC_l)MBKux8<(A#Bs1_#F-fswq$T6Z zu2IMRNnX-{nVsuQUNci#=`{(icq2WMiv!K3Opm*s^={ufwxMjOx=*IQNvC_hw7_Tx z82@CUBV=SPegUC-qrM+d{m03;;Jw4}ic`1V@_M6s?wcwL;}uFZ8R<4-R~;Q5 z<-fjwNrsTdWRKlG|DmlmSwo=e}mjzp2{xW}D~8mkyvIPjB5tC6sg>vRZXB zd(R=PBmPZ{1?=y3DeYs`DM@&)QQeyn;A&duT#4sB50%Pi3X6|y4qQ2TIAp}puSU$I zNcP4|XD)A(3@g%)OU$)dRWqmGG%4TFyKgv?(`_2{w&VTA6rA23J|s2C&UPexna?=@mqaQ`sv+rmOuId zYt$2(SIUYo;J*n-{C5ori@dsCAlv0y>R-&RHUOUnm7&u?Aj0+2`lU63zBP-Nj~`rk z7NY<5#5O!X*Wlx`yz&GLsm^b|87b8UMFUw}&6I~1E`gp^ z&GH_tY73u3?|naMn|pn1bfXGBv!^UP`@wB5tz9_g>?15NMSLP2OWpYWqx2Q7PG>M& zOJ?AtW-6LG5JG9opZ1z6!bbm5}5_ zKI7p6Kz?1CDmnBLXzXurPFoVlx%1c~yXhDa0`jf0eRM9e=hHYp5mMRDE+X zNGw42;}O+Ucxe#(v@3QcgEv6dSVqRTjI@N|LwE;U_tM>>JU`Cq+T__Wg;Yi`(&%h# z_c2YIebu`~k92M2HPI<(;U=hZwh6YEm%X!Mv#cl}^&Xeo>InlftK`|Np?KmSv>s#*Rq8Aw?njF52TQFz`L9E8&lJ!i!W}o|X zVy~4GNMsjWc@ATQZrFDm-LT2}nnnd$6y$kU(Lt+P6j~CNkh8wgv|NTjaC;a09eON9 ztl(ThxCNd;_eb>h=j&^kj;U^el%maq=Yya`bQz3#iVijgU@8dUgit zk@ADlB@FE3+5W0(&>0(82j@Of?|gNm#;bH7fza|mR`;#zq>$vDsOU#X*(r1d@6X0^ zu@?)aUjTJ+y$L%(U4@O$lEXoSb(G=Z``Y-E-pj{7U-?5?P(f>T!A+IjvOo1R0I^R-kPRs4ng1kLx`@jsr}Eb3cw)a68d^Ug7VS+rmp z-N{X4mA|>I2!0WCGRpq9&5^QFeJ$y9sF0@2ev1Vd+Zk<_BKq>`T;F>M@cwgg<**W@ SPx{X=0KtxITaP`G`u_kc;cWu| literal 0 HcmV?d00001 From 9b853f0dff126e95338daced3d716ed18873127c Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Tue, 30 Aug 2022 20:53:24 -0500 Subject: [PATCH 02/35] flesh out PrepoareProposal --- .../ADR-003-Non-interactive-defaults.md | 263 +++++++++++++++++- ....png => extra-message-that-doesnt-fit.png} | Bin ...io.png => fit-extra-msg-byremoving-tx.png} | Bin docs/architecture/assets/multirow.png | Bin 0 -> 17903 bytes 4 files changed, 251 insertions(+), 12 deletions(-) rename docs/architecture/assets/{extra.drawio.png => extra-message-that-doesnt-fit.png} (100%) rename docs/architecture/assets/{fit-by-removing-tx.drawio.png => fit-extra-msg-byremoving-tx.png} (100%) create mode 100644 docs/architecture/assets/multirow.png diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 2e93ac55c8..443f1c0929 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -2,38 +2,272 @@ ## Intro +pls see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md), from which this ADR paraphrases heavily. + Currently, when checking for message inclusion, validators recreate the share commitment from the messages in the block and compare those with what are signed over in the `MsgPayForData` transactions also in that block. If any commitment is not found in one of the PFD transactions, or if there is a commitment that doesn't have a corresponding message, then they reject that block. -While this functions as a message inclusion check, the light client has to assume that 2/3's of the voting power is honest in order to be assured that both the messages they are interested in and the rest of the messages paid for in that block are actually included. +While this functions as a message inclusion check, the light client has to assume that 2/3's of the voting power is honest in order to be assured that both the messages they are interested in and the rest of the messages paid for in that block are actually included. In order to have this property, we need a block (or tx? pls halp reviewers) validity rule where: + +> **All share commitments included in `MsgPayForData` must consist only of subtree roots of the data square.** + +The main issue with that requirement is that it requires the users to know the relevant subtree roots before they sign, which is problematic considering that is the block is not orginized perfectly, the subtree roots will include data unknown to the user at the time of signing. To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional message layout rules that allow for commitments to messages to consist entirely of sub tree roots of the data root, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: MODIFIED FROM THE SPEC +> **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** -- Messages begin at a location aligned with the largest power of 2 that is not larger than the message length or k. -- If the largest power of 2 of a given message spans multiple rows it must begin at the start of a row (this can occur if a message is longer than k shares or if the block producer decides to start a message partway through a row and it cannot fit). +![Subtree root commitment](./assets/subtree-root.png "Subtree Root based commitments") -We can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. Below illustrates how we can break a message up into two different subtree roots, the first for first four shares, the second consisting of the last two shares. +> **If the messages are larger than k, then they must start on a new row.** -![before](./assets/subtree-root.png "Subtree Root based commitments") +![Multi row share commitment](./assets/multirow.png "Subtree Root based commitments") -In practice this means that we end up adding padding between messages (zig-zag hatched share). Padding consists of a the namespace of the message before it, with all zeros for data. +If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. Below illustrates how we can break a message up into two different subtree roots, the first for first four shares, the second consisting of the last two shares. -![before](./assets/before.png "before") -![after](./assets/after.png "after") -![example](./assets/example-full-block.png "example") +In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of a the namespace of the message before it, with all zeros for data. + +![Before using the non-interactive defaults](./assets/before.png "Before requiring that all commits consist of subtree roots") +![after](./assets/after.png "After requiring that all commits consist of subtree roots") +Below is an example block that has been filled using the non-interactive default rules to ensure that all commitments consist only of subtree roots. -Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. +![example](./assets/example-full-block.png "example") +Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. -## Alternative Approaches +## Alternative Designs -Arranging the messages in the block to maximize for fees is an NP-hard problem because each change to the square potentially affects the rest of the messages in the square. There will likely be many different strategies we could use to quickly and efficiently fill the square in a valid way. +While all commitments signed over must only consist of subtree roots, its worth noting that non-interactive defaults are just that, defaults! It's entirely possible that block producers use some mechanism to notify the signer of the commitments that they must sign over, or even that the block producers are signing paying for the inclusion of the message on behalf of the users. This would render the non-interactive default rules, and the padding accompanied by them, to not be necessary. Other solutions are not mutually exclusive to non-interactive defaults, and do not even have to be built by the core team, so covering those solutions in a more in depth way is outside the scope of this ADR. However, whatever design we pick needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults, and we still need to be able to check for message inclusion using subtree roots. ## Decision +TBD + ## Detailed Design +To recap the default constraints of arranging a square: + +- All messages must be ordered lexigraphically by namespace. +- The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. +- If a `MsgPayForData` is added to the square, then its corresponding message must also be included. +- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- Transactions with higher fees should be prioritized by default. +- Ideally, the square should be filled as optimally as possible. + +For squares that are smaller than the max squaresize, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place (reviewers: is this true? halp). + +Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual compuation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Caclulating the exact number of bytes used due to our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. + +![extra message that can't fit](./assets/extra-message-that-doesnt-fit.png "extra message") +![fit the extra message by removing a tx](./assets/fit-extra-msg-byremoving-tx.png "extra message") + +To meet the above constraints, there are multiple refactors required. + +- Add metadata to wrapped transactions, connecting that transaction with message that it pays for. +- Refactor share splitting and merging to use the above metadata when decoding and encoding the square. +- Implement the non-interactive default logic. +- Implement the ability to traverse nmt tree to find subtree roots. +- Refactor square estimation to account for padding introduced by non-interactive defaults. +- Refactor `PrepareProposal` to arrange the shares such that each message has the appropriate subtree roots, and so that the metadata connection transactions and messages is correct. +- Refactor `ProcessProposal` to check for message inclusion using only subtree roots to row roots. + +### Add metadata to wrapped transactions [#819](https://github.com/celestiaorg/celestia-core/pull/819) + +In order to check for message inclusion, create message inclusion fraud proofs, split the block data into squares, and not force non-interactive defaults for every square, we have to connect a `MsgPayForData` transaction to its corresponding messasge. Since users cannot know this ahead of time, block producers have to add this information as metadata before the transaction gets included in the block. + +We are already wrapping/unwrapping malleated transactions, so including the `share_index` as metadata using the current code is essentially as simple as adding the `share_index` to the struct. Transactions are unwrapped selectively by using a [`MalleatedTxDecoder`](https://github.com/celestiaorg/celestia-app/blob/5ac236fb1dab6628e98a505269f295c18e150b27/app/encoding/malleated_tx_decoder.go#L8-L15) or by using the [`UnwrapMalleatedTx`](https://github.com/celestiaorg/celestia-core/blob/212901fcfc0f5a095683b1836ea9e890cc952dc7/types/tx.go#L214-L237) function. + +```proto +message MalleatedTx { + bytes original_tx_hash = 1; + bytes tx = 2; + uint32 share_index = 3; +} +``` + +### Refactor Share Splitting and Merging + +Our encoding scheme now has to actually use the meta data added to wrapped transaction. + +Note: In order to properly test the new encoding scheme, we have perform identical if not very similar application logic to that in `PrepareProposal` for this reason, we wanted initially wanted to move the share encoding/decoding logic to the app instead of core. There were some other quality of life improvements that were also added during this refactor that are technically unrelated to these changes. + +We currently utilize a struct to store the state needed for lazily writing message shares (todo: possibly change this name). Here we add a method to it that allows for us to write namepsaced padded shares. + +```go +// MessageShareSplitter lazily splits messages into shares that will eventually be +// included in a data square. It also has methods to help progressively count +// how many shares the messages written take up. +type MessageShareSplitter struct { + shares [][]NamespacedShare + count int +} +... +// WriteNamespacedPaddedShares adds empty shares using the namespace of the last written share. +// This is useful to follow the message layout rules. It assumes that at least +// one share has already been written, if not it panics. +func (msw *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { + if len(msw.shares) == 0 { + panic("Cannot write empty namespaced shares on an empty MessageShareSplitter") + } + if count == 0 { + return + } + lastMessage := msw.shares[len(msw.shares)-1] + msw.shares = append(msw.shares, namespacedPaddedShares(lastMessage[0].ID, count)) + msw.count += count +} +``` + +Now we simply combine this new functionality with the `share_index`s described above, and we can properly split and pad messages when needed. Note, the below implementation allows for `nil` to be passed as indexes. This is important, as it allows the same implmenetation to be used in the cases where we don't want to split messages using wrapped transactions, such as supporting older networks or when users create commitments to sign over for `MsgWirePayForData` + +```go +func SplitMessages(cursor int, indexes []uint32, msgs []coretypes.Message) ([][]byte, error) { + if indexes != nil && len(indexes) != len(msgs) { + return nil, ErrIncorrectNumberOfIndexes + } + writer := NewMessageShareSplitter() + for i, msg := range msgs { + writer.Write(msg) + if indexes != nil && len(indexes) > i+1 { + paddedShareCount := int(indexes[i+1]) - (writer.Count() + cursor) + writer.WriteNamespacedPaddedShares(paddedShareCount) + } + } + return writer.Export().RawShares(), nil +} +``` + +When parsing the message shares, we can simply ignore these added namespaced padded shares. + +### Implement the non-interactive default logic + +recall our non-interactive default rule: + +> **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** + +The key to arranging the square into non-interactive defaults is calculating then next "aligned power of 2". We do that here statelessly with two simple functions. + +```go +// NextAlignedPowerOfTwo calculates the next index in a row that is an aligned +// power of two and returns false if the entire the msg cannot fit on the given +// row at the next aligned power of two. An aligned power of two means that the +// largest power of two that fits entirely in the msg or the square size. pls +// see specs for further details. Assumes that cursor < k, all args are non +// negative, and that k is a power of two. +// https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules +func NextAlignedPowerOfTwo(cursor, msgLen, k int) (int, bool) { + // if we're starting at the beginning of the row, then return as there are + // no cases where we don't start at 0. + if cursor == 0 || cursor%k == 0 { + return cursor, true + } + + nextLowest := nextLowestPowerOfTwo(msgLen) + endOfCurrentRow := ((cursor / k) + 1) * k + cursor = roundUpBy(cursor, nextLowest) + switch { + // the entire message fits in this row + case cursor+msgLen <= endOfCurrentRow: + return cursor, true + // only a portion of the message fits in this row + case cursor+nextLowest <= endOfCurrentRow: + return cursor, false + // none of the message fits on this row, so return the start of the next row + default: + return endOfCurrentRow, false + } +} + +// roundUpBy rounds cursor up to the next interval of v. If cursor is divisible +// by v, then it returns cursor +func roundUpBy(cursor, v int) int { + switch { + case cursor == 0: + return cursor + case cursor%v == 0: + return cursor + default: + return ((cursor / v) + 1) * v + } +} +``` + +We can now use this function in many places, such as when we estimate the square size, calculate the number of messages used, calculate which subtree roots are needed to verify a share commitment, and calculate when to start the first message after the reserved namespaces are filled. + +### Implement the ability to traverse an nmt tree to find subtree roots + +todo: to after implementing feedback + +### Refactor `PrepareProposal` + +From a very high level perspective `PrepareProposal` stays mostly the same. We need to estimate the square size accurately enough to malleate the transactions that are given to us by tendermint, then arrange messages in a square. However, recall the constraints and issues described at the top of this section. + +- All messages must be ordered lexigraphically by namespace. +- The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. +- If a `MsgPayForData` is added to the square, then its corresponding message must also be included. +- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- Transactions with higher fees should be prioritized by default. +- Ideally, the square should be filled as optimally as possible. + +These constraints make processing block data into a square much more complicated. + +#### Square Estimation + +Using some of the non-interactive defaults code above, we can quickly calculate the size of each reserved namespace shares, along with + +```go +// FitsInSquare uses the non interactive default rules to see if messages of +// some lengths will fit in a square of size origSquareSize starting at share +// index cursor. See non-interactive default rules +// https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules +func FitsInSquare(cursor, origSquareSize int, msgShareLens ...int) (bool, int) { + // if there are 0 messages and the cursor already fits inside the square, + // then we already know that everything fits in the square. + if len(msgShareLens) == 0 && cursor/origSquareSize <= origSquareSize { + return true, 0 + } + firstMsgLen := 1 + if len(msgShareLens) > 0 { + firstMsgLen = msgShareLens[0] + } + // here we account for padding between the contiguous and message shares + cursor, _ = NextAlignedPowerOfTwo(cursor, firstMsgLen, origSquareSize) + sharesUsed, _ := MsgSharesUsedNIDefaults(cursor, origSquareSize, msgShareLens...) + return cursor+sharesUsed <= origSquareSize*origSquareSize, sharesUsed +} + +// estimateSquareSize uses the provided block data to estimate the square size +// assuming that all malleated txs follow the non interactive default rules. +// todo: get rid of the second shares used int as its not used atm +func estimateSquareSize(txs []*parsedTx, evd core.EvidenceList) (uint64, int) { + // get the raw count of shares taken by each type of block data + txShares, evdShares, msgLens := rawShareCount(txs, evd) + ... + + var fits bool + for { + // assume that all the msgs in the square use the non-interactive + // default rules and see if we can fit them in the smallest starting + // square size. We start the cusor (share index) at the begginning of + // the message shares (txShares+evdShares), because shares that do not + // follow the non-interactive defaults are simple to estimate. + fits, msgShares = shares.FitsInSquare(txShares+evdShares, squareSize, msgLens...) + switch { + // stop estimating if we know we can reach the max square size + case squareSize >= consts.MaxSquareSize: + return consts.MaxSquareSize, txShares + evdShares + msgShares + // return if we've found a square size that fits all of the txs + case fits: + return uint64(squareSize), txShares + evdShares + msgShares + // try the next largest square size if we can't fit all the txs + case !fits: + // increment the square size + squareSize = int(nextPowerOfTwo(squareSize + 1)) + } + } +} +``` + ## Status {Deprecated|Proposed|Accepted|Declined} @@ -42,8 +276,13 @@ Arranging the messages in the block to maximize for fees is an NP-hard problem b ### Positive +- Trust minimized message inclusion checks +- Ability to create message inclusion fraud proofs + ### Negative +- Potentially there will be a lot of wasted square space + ### Neutral ## References diff --git a/docs/architecture/assets/extra.drawio.png b/docs/architecture/assets/extra-message-that-doesnt-fit.png similarity index 100% rename from docs/architecture/assets/extra.drawio.png rename to docs/architecture/assets/extra-message-that-doesnt-fit.png diff --git a/docs/architecture/assets/fit-by-removing-tx.drawio.png b/docs/architecture/assets/fit-extra-msg-byremoving-tx.png similarity index 100% rename from docs/architecture/assets/fit-by-removing-tx.drawio.png rename to docs/architecture/assets/fit-extra-msg-byremoving-tx.png diff --git a/docs/architecture/assets/multirow.png b/docs/architecture/assets/multirow.png new file mode 100644 index 0000000000000000000000000000000000000000..dd9f983ff889ddef8f2b6801c5fd5e59c14283c9 GIT binary patch literal 17903 zcmZ6y2UJr*^9Onp0*0axKtYif5dj550tui(fP@-)2_Q%(1W4$FPOu*^3p z0RRdC(<^W`@F{xgqYd~2@i*1h07}1~oB{xjqX9 vpc)yow)jnVvX>NFbV?(H9N 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 Date: Wed, 31 Aug 2022 22:26:15 -0500 Subject: [PATCH 03/35] add processproposal --- .../ADR-003-Non-interactive-defaults.md | 651 ++++++++++++++---- 1 file changed, 529 insertions(+), 122 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 443f1c0929..949275f7da 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -1,5 +1,9 @@ # ADR 003: Non-interactive Defaults, Wrapped Transactions, and Subtree Root Message Inclusion Checks +NOTE: Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs. + +The exact approach taken by the initial implementation, however, are certainly up for scrutiny. In this specific case, if there are significant changes proposed, then we might want to implement those improvements in other ADRs/PRs considering that we want to switch to a functioning version of non-interactive defaults as soon as possible. + ## Intro pls see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md), from which this ADR paraphrases heavily. @@ -10,7 +14,7 @@ While this functions as a message inclusion check, the light client has to assum > **All share commitments included in `MsgPayForData` must consist only of subtree roots of the data square.** -The main issue with that requirement is that it requires the users to know the relevant subtree roots before they sign, which is problematic considering that is the block is not orginized perfectly, the subtree roots will include data unknown to the user at the time of signing. +The main issue with that requirement is that it requires the users to know the relevant subtree roots before they sign, which is problematic considering that is the block is not organized perfectly, the subtree roots will include data unknown to the user at the time of signing. To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional message layout rules that allow for commitments to messages to consist entirely of sub tree roots of the data root, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: MODIFIED FROM THE SPEC @@ -24,7 +28,7 @@ To fix this, the spec outlines the “non-interactive default rules”. These in If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. Below illustrates how we can break a message up into two different subtree roots, the first for first four shares, the second consisting of the last two shares. -In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of a the namespace of the message before it, with all zeros for data. +In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of the namespace of the message before it, with all zeros for data. ![Before using the non-interactive defaults](./assets/before.png "Before requiring that all commits consist of subtree roots") ![after](./assets/after.png "After requiring that all commits consist of subtree roots") @@ -35,105 +39,110 @@ Below is an example block that has been filled using the non-interactive default Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. +## Decision + +TBD + +While there certainly can be some decisions here, whether or not we begin following the non-interactive defaults isn't really the goal of this ADR. Please the note at the top of this document. + ## Alternative Designs -While all commitments signed over must only consist of subtree roots, its worth noting that non-interactive defaults are just that, defaults! It's entirely possible that block producers use some mechanism to notify the signer of the commitments that they must sign over, or even that the block producers are signing paying for the inclusion of the message on behalf of the users. This would render the non-interactive default rules, and the padding accompanied by them, to not be necessary. Other solutions are not mutually exclusive to non-interactive defaults, and do not even have to be built by the core team, so covering those solutions in a more in depth way is outside the scope of this ADR. However, whatever design we pick needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults, and we still need to be able to check for message inclusion using subtree roots. +As the first note of this document describes, the purpose of this document is not really to decide wether or not we're implementing non-interactive defaults, that has already been decided. While the exact details of the implementation are certainly up for scrutiny, those should be discussed in a different ADR -## Decision +While all commitments signed over must only consist of subtree roots, its worth noting that non-interactive defaults are just that, defaults! It's entirely possible that block producers use some mechanism to notify the signer of the commitments that they must sign over, or even that the block producers are signing paying for the inclusion of the message on behalf of the users. This would render the non-interactive defaults, and the padding accompanied by them, to not be necessary. Other solutions are not mutually exclusive to non-interactive defaults, and do not even have to be built by the core team, so covering those solutions in a more in depth way is outside the scope of this ADR. -TBD +However, the default implementation of non-interative defaults is within the scope of this ADR. Whatever design we use ultimately needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults, and we still need to be able to check for message inclusion using subtree roots. ## Detailed Design To recap the default constraints of arranging a square: -- All messages must be ordered lexigraphically by namespace. +- All messages must be ordered lexicographically by namespace. - The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. - There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). - Transactions with higher fees should be prioritized by default. - Ideally, the square should be filled as optimally as possible. -For squares that are smaller than the max squaresize, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place (reviewers: is this true? halp). +For squares that are smaller than the max squaresize, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place. -Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual compuation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Caclulating the exact number of bytes used due to our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. +Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual computation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Calculating the exact number of bytes used is further complicated by the order of the steps due to our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. ![extra message that can't fit](./assets/extra-message-that-doesnt-fit.png "extra message") ![fit the extra message by removing a tx](./assets/fit-extra-msg-byremoving-tx.png "extra message") To meet the above constraints, there are multiple refactors required. -- Add metadata to wrapped transactions, connecting that transaction with message that it pays for. +- Add metadata to wrapped transactions, connecting that transaction with a message that it pays for. - Refactor share splitting and merging to use the above metadata when decoding and encoding the square. - Implement the non-interactive default logic. - Implement the ability to traverse nmt tree to find subtree roots. -- Refactor square estimation to account for padding introduced by non-interactive defaults. -- Refactor `PrepareProposal` to arrange the shares such that each message has the appropriate subtree roots, and so that the metadata connection transactions and messages is correct. +- Refactor `PrepareProposal` to arrange the shares such that each message has the appropriate subtree roots, and so that the metadata connection between transactions and messages is correct. - Refactor `ProcessProposal` to check for message inclusion using only subtree roots to row roots. ### Add metadata to wrapped transactions [#819](https://github.com/celestiaorg/celestia-core/pull/819) -In order to check for message inclusion, create message inclusion fraud proofs, split the block data into squares, and not force non-interactive defaults for every square, we have to connect a `MsgPayForData` transaction to its corresponding messasge. Since users cannot know this ahead of time, block producers have to add this information as metadata before the transaction gets included in the block. +In order to check for message inclusion, create message inclusion fraud proofs, split the block data into squares, and not force non-interactive defaults for every square, we have to connect a `MsgPayForData` transaction to its corresponding message. Since users cannot know this ahead of time, block producers have to add this information as metadata before the transaction gets included in the block. We are already wrapping/unwrapping malleated transactions, so including the `share_index` as metadata using the current code is essentially as simple as adding the `share_index` to the struct. Transactions are unwrapped selectively by using a [`MalleatedTxDecoder`](https://github.com/celestiaorg/celestia-app/blob/5ac236fb1dab6628e98a505269f295c18e150b27/app/encoding/malleated_tx_decoder.go#L8-L15) or by using the [`UnwrapMalleatedTx`](https://github.com/celestiaorg/celestia-core/blob/212901fcfc0f5a095683b1836ea9e890cc952dc7/types/tx.go#L214-L237) function. ```proto message MalleatedTx { - bytes original_tx_hash = 1; - bytes tx = 2; - uint32 share_index = 3; +bytes original_tx_hash = 1; +bytes tx = 2; +uint32 share_index = 3; } ``` ### Refactor Share Splitting and Merging -Our encoding scheme now has to actually use the meta data added to wrapped transaction. +Our encoding scheme now has to actually use the metadata added to wrapped transactions. -Note: In order to properly test the new encoding scheme, we have perform identical if not very similar application logic to that in `PrepareProposal` for this reason, we wanted initially wanted to move the share encoding/decoding logic to the app instead of core. There were some other quality of life improvements that were also added during this refactor that are technically unrelated to these changes. +Note: In order to properly test the new encoding scheme, we have to perform identical if not very similar application logic to that in `PrepareProposal` for this reason, we initially wanted to move the share encoding/decoding logic to the app instead of core. There were some other quality of life improvements that were also added during this refactor that are technically unrelated to these changes. -We currently utilize a struct to store the state needed for lazily writing message shares (todo: possibly change this name). Here we add a method to it that allows for us to write namepsaced padded shares. +We currently utilize a struct to store the state needed for lazily writing message shares (todo: possibly change this name). Here we add a method to it that allows for us to write namespaced padded shares. ```go // MessageShareSplitter lazily splits messages into shares that will eventually be // included in a data square. It also has methods to help progressively count // how many shares the messages written take up. type MessageShareSplitter struct { - shares [][]NamespacedShare - count int + shares [][]NamespacedShare + count int } ... // WriteNamespacedPaddedShares adds empty shares using the namespace of the last written share. // This is useful to follow the message layout rules. It assumes that at least // one share has already been written, if not it panics. func (msw *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { - if len(msw.shares) == 0 { - panic("Cannot write empty namespaced shares on an empty MessageShareSplitter") - } - if count == 0 { - return - } - lastMessage := msw.shares[len(msw.shares)-1] - msw.shares = append(msw.shares, namespacedPaddedShares(lastMessage[0].ID, count)) - msw.count += count + if len(msw.shares) == 0 { + panic("Cannot write empty namespaced shares on an empty MessageShareSplitter") + } + if count == 0 { + return + } + lastMessage := msw.shares[len(msw.shares)-1] + msw.shares = append(msw.shares, namespacedPaddedShares(lastMessage[0].ID, count)) + msw.count += count } ``` -Now we simply combine this new functionality with the `share_index`s described above, and we can properly split and pad messages when needed. Note, the below implementation allows for `nil` to be passed as indexes. This is important, as it allows the same implmenetation to be used in the cases where we don't want to split messages using wrapped transactions, such as supporting older networks or when users create commitments to sign over for `MsgWirePayForData` +Now we simply combine this new functionality with the `share_index`s described above, and we can properly split and pad messages when needed. Note, the below implementation allows for `nil` to be passed as indexes. This is important, as it allows the same implementation to be used in the cases where we don't want to split messages using wrapped transactions, such as supporting older networks or when users create commitments to sign over for `MsgWirePayForData` ```go func SplitMessages(cursor int, indexes []uint32, msgs []coretypes.Message) ([][]byte, error) { - if indexes != nil && len(indexes) != len(msgs) { - return nil, ErrIncorrectNumberOfIndexes - } - writer := NewMessageShareSplitter() - for i, msg := range msgs { - writer.Write(msg) - if indexes != nil && len(indexes) > i+1 { - paddedShareCount := int(indexes[i+1]) - (writer.Count() + cursor) - writer.WriteNamespacedPaddedShares(paddedShareCount) - } - } - return writer.Export().RawShares(), nil + if indexes != nil && len(indexes) != len(msgs) { + return nil, ErrIncorrectNumberOfIndexes + } + writer := NewMessageShareSplitter() + for i, msg := range msgs { + writer.Write(msg) + if indexes != nil && len(indexes) > i+1 { + paddedShareCount := int(indexes[i+1]) - (writer.Count() + cursor) + writer.WriteNamespacedPaddedShares(paddedShareCount) + } + } + return writer.Export().RawShares(), nil } ``` @@ -156,64 +165,146 @@ The key to arranging the square into non-interactive defaults is calculating the // negative, and that k is a power of two. // https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules func NextAlignedPowerOfTwo(cursor, msgLen, k int) (int, bool) { - // if we're starting at the beginning of the row, then return as there are - // no cases where we don't start at 0. - if cursor == 0 || cursor%k == 0 { - return cursor, true - } - - nextLowest := nextLowestPowerOfTwo(msgLen) - endOfCurrentRow := ((cursor / k) + 1) * k - cursor = roundUpBy(cursor, nextLowest) - switch { - // the entire message fits in this row - case cursor+msgLen <= endOfCurrentRow: - return cursor, true - // only a portion of the message fits in this row - case cursor+nextLowest <= endOfCurrentRow: - return cursor, false - // none of the message fits on this row, so return the start of the next row - default: - return endOfCurrentRow, false - } + // if we're starting at the beginning of the row, then return as there are + // no cases where we don't start at 0. + if cursor == 0 || cursor%k == 0 { + return cursor, true + } + + nextLowest := nextLowestPowerOfTwo(msgLen) + endOfCurrentRow := ((cursor / k) + 1) * k + cursor = roundUpBy(cursor, nextLowest) + switch { + // the entire message fits in this row + case cursor+msgLen <= endOfCurrentRow: + return cursor, true + // only a portion of the message fits in this row + case cursor+nextLowest <= endOfCurrentRow: + return cursor, false + // none of the message fits on this row, so return the start of the next row + default: + return endOfCurrentRow, false + } } // roundUpBy rounds cursor up to the next interval of v. If cursor is divisible // by v, then it returns cursor func roundUpBy(cursor, v int) int { - switch { - case cursor == 0: - return cursor - case cursor%v == 0: - return cursor - default: - return ((cursor / v) + 1) * v - } + switch { + case cursor == 0: + return cursor + case cursor%v == 0: + return cursor + default: + return ((cursor / v) + 1) * v + } } ``` We can now use this function in many places, such as when we estimate the square size, calculate the number of messages used, calculate which subtree roots are needed to verify a share commitment, and calculate when to start the first message after the reserved namespaces are filled. -### Implement the ability to traverse an nmt tree to find subtree roots +### Refactor `PrepareProposal` -todo: to after implementing feedback +From a very high level perspective `PrepareProposal` stays mostly the same. We need to estimate the square size accurately enough to pick a square size so that we can malleate the transactions that are given to us by tendermint, then arrange messages in a square. However, recall the constraints and issues described at the top of this section. Technically, the addition or removal of a single byte can change the entire arrangement of the square. Knowing, or at least being able to estimate how many shares/bytes are used is critical to finding an optimal solution to arranging the square yet the constraints themselves along with our frequent use of variable length encoding techniques make estimating much more complicated. -### Refactor `PrepareProposal` +While messages must be ordered lexicographically, we also have to order transactions by their fees and ensure that each message is added atomically with its corresponding `MsgPayForData` transaction. Also, malleated transactions exist alongside normal transactions, the former of which we have to add **variable sized** metadata to only _after_ we know the starting location of each message. All while following the non-interactive defaults, both of which make it difficult to accurately estimate the number of shares or bytes used. -From a very high level perspective `PrepareProposal` stays mostly the same. We need to estimate the square size accurately enough to malleate the transactions that are given to us by tendermint, then arrange messages in a square. However, recall the constraints and issues described at the top of this section. +Below is the lightly summarized code for `PrepareProposal` that we can use a high level map of what we're doing to arrange the block data into a square. -- All messages must be ordered lexigraphically by namespace. -- The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. -- If a `MsgPayForData` is added to the square, then its corresponding message must also be included. -- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). -- Transactions with higher fees should be prioritized by default. -- Ideally, the square should be filled as optimally as possible. +```go +// PrepareProposal fulfills the celestia-core version of the ABCI 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 back +// to tendermint via the blockdata. +func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + // parse the txs, extracting any MsgWirePayForData and performing basic + // validation for each transaction. Invalid txs are ignored. Original order + // of the txs is maintained. + parsedTxs := parseTxs(app.txConfig, req.BlockData.Txs) + + // estimate the square size. This estimation errors on the side of larger + // squares but can only return values within the min and max square size. + squareSize, totalSharesUsed := estimateSquareSize(parsedTxs, req.BlockData.Evidence) + + // the totalSharesUsed can be larger that the max number of shares if we + // reach the max square size. In this case, we must prune the deprioritized + // txs (and their messages if they're pfd txs). + if totalSharesUsed > int(squareSize*squareSize) { + parsedTxs = prune(app.txConfig, parsedTxs, totalSharesUsed, int(squareSize)) + } + + // in this step we are processing any MsgWirePayForData transactions into + // MsgPayForData and their respective messages. The malleatedTxs contain the + // the new sdk.Msg with the original tx's metadata (sequence number, gas + // price etc). + processedTxs, messages, err := malleateTxs(app.txConfig, squareSize, parsedTxs, req.BlockData.Evidence) + if err != nil { + panic(err) + } + + blockData := core.Data{ + Txs: processedTxs, + Evidence: req.BlockData.Evidence, + Messages: core.Messages{MessagesList: messages}, + OriginalSquareSize: squareSize, + } + + ... + + // create the new data root by creating the data availability header (merkle + // roots of each row and col of the erasure data). + dah := da.NewDataAvailabilityHeader(eds) + + // We use the block data struct to pass the square size and calculated data + // root to tendermint. + blockData.Hash = dah.Hash() + blockData.OriginalSquareSize = squareSize + + // tendermint doesn't need to use any of the erasure data, as only the + // protobuf encoded version of the block data is gossiped. + return abci.ResponsePrepareProposal{ + BlockData: &blockData, + } +} +``` + +#### ParsedTxs + +The first major change is that we are making use of an intermediate data structure. It contains fields that are progressively and optionally used during the malleation process. This makes it easier to keep track of malleated transactions and their messages, prune transactions in the case that we go over the max square size, cache the decoded transactions avoiding excessive deserialization, and add metadata to malleated transactions after we malleate them. All while preserving the original ordering (from the prioritized mempool) of the transactions. + +```go +// parsedTx is an interanl struct that keeps track of potentially valid txs and +// their wire messages if they have any. +type parsedTx struct { + // the original raw bytes of the tx + rawTx []byte + // tx is the parsed sdk tx. this is nil for all txs that do not contain a + // MsgWirePayForData, as we do not need to parse other types of of transactions + tx signing.Tx + // msg is the wire msg if it exists in the tx. This field is nil for all txs + // that do not contain one. + msg *types.MsgWirePayForData + // malleatedTx is the transaction after the malleation process is performed. This is nil until that process has been completed for viable transactions. + malleatedTx coretypes.Tx +} +``` -These constraints make processing block data into a square much more complicated. +```go +func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + // parse the txs, extracting any MsgWirePayForData and performing basic + // validation for each transaction. Invalid txs are ignored. Original order + // of the txs is maintained. + parsedTxs := parseTxs(app.txConfig, req.BlockData.Txs) + ... +} +``` #### Square Estimation -Using some of the non-interactive defaults code above, we can quickly calculate the size of each reserved namespace shares, along with +Using some of the non-interactive defaults code above, we can quickly calculate the size of each reserved namespace shares using the parsed transactions. As discussed in the docs of this function, the goal here is not necessarily to get a perfect count of the shares that are being used, but we do need to know roughly what square size is needed. When estimating, we should round up in square size. ```go // FitsInSquare uses the non interactive default rules to see if messages of @@ -221,53 +312,368 @@ Using some of the non-interactive defaults code above, we can quickly calculate // index cursor. See non-interactive default rules // https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules func FitsInSquare(cursor, origSquareSize int, msgShareLens ...int) (bool, int) { - // if there are 0 messages and the cursor already fits inside the square, - // then we already know that everything fits in the square. - if len(msgShareLens) == 0 && cursor/origSquareSize <= origSquareSize { - return true, 0 - } - firstMsgLen := 1 - if len(msgShareLens) > 0 { - firstMsgLen = msgShareLens[0] - } - // here we account for padding between the contiguous and message shares - cursor, _ = NextAlignedPowerOfTwo(cursor, firstMsgLen, origSquareSize) - sharesUsed, _ := MsgSharesUsedNIDefaults(cursor, origSquareSize, msgShareLens...) - return cursor+sharesUsed <= origSquareSize*origSquareSize, sharesUsed + // if there are 0 messages and the cursor already fits inside the square, + // then we already know that everything fits in the square. + if len(msgShareLens) == 0 && cursor/origSquareSize <= origSquareSize { + return true, 0 + } + firstMsgLen := 1 + if len(msgShareLens) > 0 { + firstMsgLen = msgShareLens[0] + } + // here we account for padding between the contiguous and message shares + cursor, _ = NextAlignedPowerOfTwo(cursor, firstMsgLen, origSquareSize) + sharesUsed, _ := MsgSharesUsedNIDefaults(cursor, origSquareSize, msgShareLens...) + return cursor+sharesUsed <= origSquareSize*origSquareSize, sharesUsed } // estimateSquareSize uses the provided block data to estimate the square size // assuming that all malleated txs follow the non interactive default rules. -// todo: get rid of the second shares used int as its not used atm +// The total shares used is returned to allow for pruning if necessary. func estimateSquareSize(txs []*parsedTx, evd core.EvidenceList) (uint64, int) { - // get the raw count of shares taken by each type of block data - txShares, evdShares, msgLens := rawShareCount(txs, evd) - ... - - var fits bool - for { - // assume that all the msgs in the square use the non-interactive - // default rules and see if we can fit them in the smallest starting - // square size. We start the cusor (share index) at the begginning of - // the message shares (txShares+evdShares), because shares that do not - // follow the non-interactive defaults are simple to estimate. - fits, msgShares = shares.FitsInSquare(txShares+evdShares, squareSize, msgLens...) - switch { - // stop estimating if we know we can reach the max square size - case squareSize >= consts.MaxSquareSize: - return consts.MaxSquareSize, txShares + evdShares + msgShares - // return if we've found a square size that fits all of the txs - case fits: - return uint64(squareSize), txShares + evdShares + msgShares - // try the next largest square size if we can't fit all the txs - case !fits: - // increment the square size - squareSize = int(nextPowerOfTwo(squareSize + 1)) - } - } + // get the raw count of shares taken by each type of block data + txShares, evdShares, msgLens := rawShareCount(txs, evd) + ... + + var fits bool + for { + // assume that all the msgs in the square use the non-interactive + // default rules and see if we can fit them in the smallest starting + // square size. We start the cursor (share index) at the beginning of + // the message shares (txShares+evdShares), because shares that do not + // follow the non-interactive defaults are simple to estimate. + fits, msgShares = shares.FitsInSquare(txShares+evdShares, squareSize, msgLens...) + switch { + // stop estimating if we know we can reach the max square size + case squareSize >= consts.MaxSquareSize: + return consts.MaxSquareSize, txShares + evdShares + msgShares + // return if we've found a square size that fits all of the txs + case fits: + return uint64(squareSize), txShares + evdShares + msgShares + // try the next largest square size if we can't fit all the txs + case !fits: + // increment the square size + squareSize = int(nextPowerOfTwo(squareSize + 1)) + } + } } ``` +#### Pruning excess transactions + +If there are too many transactions and messages in the square to fit in the max square size, then we have to remove them from the block. This can be complicated, as by default we want to prioritzie transactions that have higher fees, but removing a low fee transaction doesn't always result in using less shares. + +The simplest approach, and the one taken in the initial implementation, works by prematurely pruning the txs if we estimate that too many shares are being used. While this does work, and fulfills the constraints discussed earlier to create valid blocks, it is suboptimal. Ideally we would be able to identify the most optimal message and transactions to remove and simply remove only those. As mentioned earlier, technically, a single byte difference could change the entire arrangement of the square. Which makes arranging the square with complete confidence difficult not only because we have to follow all of the constraints, but also because of our frequent reliance on variable length length delimiters, and protofuf changing the amount of bytes used depending on the size of ints/uints. + + +```go +func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + ... + // the totalSharesUsed can be larger that the max number of shares if we + // reach the max square size. In this case, we must prune the deprioritized + // txs (and their messages if they're pfd txs). + if totalSharesUsed > int(squareSize*squareSize) { + parsedTxs = prune(app.txConfig, parsedTxs, totalSharesUsed, int(squareSize)) + } + ... +``` + +#### Malleation + +Due to the use of the `parsedTxs` data structure, we can now abstract the malleation process entirely. Whereas before it was hard coded into the share proprietary proposal share splitting logic. + +```go +func (p *parsedTx) malleate(txConf client.TxConfig, squareSize uint64) error { + if p.msg == nil || p.tx == nil { + return errors.New("can only malleate a tx with a MsgWirePayForData") + } + + // parse wire message and create a single message + _, unsignedPFD, sig, err := types.ProcessWirePayForData(p.msg, squareSize) + if err != nil { + return err + } + + // create the signed PayForData using the fees, gas limit, and sequence from + // the original transaction, along with the appropriate signature. + signedTx, err := types.BuildPayForDataTxFromWireTx(p.tx, txConf.NewTxBuilder(), sig, unsignedPFD) + if err != nil { + return err + } + + rawProcessedTx, err := txConf.TxEncoder()(signedTx) + if err != nil { + return err + } + + p.malleatedTx = rawProcessedTx + return nil +} +``` + +When doing this process over all of the transactions, we also need to add the share index as metadata to the malleated transaction when we wrap it. This is completed in the malleateTxs step. + +```go + +func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + ... + // in this step we are processing any MsgWirePayForData transactions into + // MsgPayForData and their respective messages. The malleatedTxs contain the + // the new sdk.Msg with the original tx's metadata (sequence number, gas + // price etc). + processedTxs, messages, err := malleateTxs(app.txConfig, squareSize, parsedTxs, req.BlockData.Evidence) + if err != nil { + panic(err) + } + ... +``` + +#### Encoding the square + +As briefly discussed earlier, one major change in how we are producing blocks is that we are using the normal mechanism for splitting shares. + +```go +func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + ... + blockData := core.Data{ + Txs: processedTxs, + Evidence: req.BlockData.Evidence, + Messages: core.Messages{MessagesList: messages}, + OriginalSquareSize: squareSize, + } + + dataSquare, err := shares.Split(coreData) + if err != nil { + panic(err) + } + ... +} +``` + +### ProcessProposal + +Fortunately, most of the work necessary for non-interactive defaults is encapsulated by `PrepareProposal`. Our goal in `ProcessProposal` is to enforce the constraints that we set during `PrepareProposal`. Note that we cannot actually check the last two constraints, so we don't. + +- All messages must be ordered lexicographically by namespace. +- The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. +- If a `MsgPayForData` is added to the square, then its corresponding message must also be included. +- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). + +We are already checking the first constraint simply be calculating the data root. The only changes we need to make here are to cache the nmt trees generated when comparing the data root, and then use those cached trees to find the subtree roots necessary to create the data commitments. + + + +#### Implement the ability to traverse an nmt tree to find subtree roots + +We need to be able to check for message inclusion using only subtree roots, and in order to do that we have to first know which subtree roots are needed. Given a message's starting position and length, we should be able to calculate that. + +```go +// coord identifies a tree node using the depth and position +// Depth Position +// 0 0 +// / \ +// / \ +// 1 0 1 +// /\ /\ +// 2 0 1 2 3 +// /\ /\ /\ /\ +// 3 0 1 2 3 4 5 6 7 +type coord struct { + // depth is the typical depth of a tree, 0 being the root + depth uint64 + // position is the index of a node of a given depth, 0 being the left most + // node + position uint64 +} + +// calculateSubTreeRootCoordinates generates the subtree root coordinates of a +// set of shares for a balanced binary tree of a given depth. It assumes that +// end does not exceed the range of a tree of the provided depth, and that end +// >= start. This function works by starting at the first index of the msg and +// working our way right. +func calculateSubTreeRootCoordinates(maxDepth, start, end uint64) []coord { + ... +} +``` + +This is effectively calculating the positions of subtree root A and subtree root B in the diagram below. + +![Subtree root commitment](./assets/subtree-root.png "Subtree Root based commitments") + +While we could regenerate the commitments using the data square, since we already have to calculate the data root during `ProcessProposal`, we cache them instead. + +```go +// subTreeRootCacher keep track of all the inner nodes of an nmt using a simple +// map. Note: this cacher does not cache individual leaves or their hashes, only +// inner nodes. +type subTreeRootCacher struct { + cache map[string][2]string +} + +func newSubTreeRootCacher() *subTreeRootCacher { + return &subTreeRootCacher{cache: make(map[string][2]string)} +} + +// Visit fulfills the nmt.NodeVisitorFn function definition. It stores each inner +// node in a simple map, which can later be used to walk the tree. This function +// is called by the nmt when calculating the root. +func (strc *subTreeRootCacher) Visit(hash []byte, children ...[]byte) { + switch len(children) { + case 2: + strc.cache[string(hash)] = [2]string{string(children[0]), string(children[1])} + case 1: + return + default: + panic("unexpected visit") + } +} + +// EDSSubTreeRootCacher caches the inner nodes for each row so that we can +// traverse it later to check for message inclusion. NOTE: Currently this has to +// use a leaky abstraction (see docs on counter field below), and is not +// threadsafe, but with a future refactor, we could simply read from rsmt2d and +// not use the tree constructor which would fix both of these issues. +type EDSSubTreeRootCacher struct { + caches []*subTreeRootCacher + squareSize uint64 + // counter is used to ignore columns NOTE: this is a leaky abstraction that + // we make because rsmt2d is used to generate the roots for us, so we have + // to assume that it will generate a row root every other tree constructed. + // This is also one of the reasons this implementation is not thread safe. + // Please see note above on a better refactor. + counter int +} + +func NewCachedSubtreeCacher(squareSize uint64) *EDSSubTreeRootCacher { + return &EDSSubTreeRootCacher{ + caches: []*subTreeRootCacher{}, + squareSize: squareSize, + } +} + +// Constructor fulfills the rsmt2d.TreeCreatorFn by keeping a pointer to the +// cache and embedding it as a nmt.NodeVisitor into a new wrapped nmt. +func (stc *EDSSubTreeRootCacher) Constructor() rsmt2d.Tree { + +} + +func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { + ... + cacher := inclusion.NewSubtreeCacher(data.OriginalSquareSize) + eds, err := rsmt2d.ComputeExtendedDataSquare(dataSquare, consts.DefaultCodec(), cacher.Constructor) + if err != nil { + ... + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_REJECT, + } + } +} +``` + +The end API should only require the cached trees, the row roots, the message start index, and the length of the message. + +```go +func GetCommit(cacher *EDSSubTreeRootCacher, dah da.DataAvailabilityHeader, start, msgShareLen int) ([]byte, error) { + ... + paths := calculateCommitPaths(originalSquareSize, start, msgShareLen) + commits := make([][]byte, len(paths)) + for i, path := range paths { + ... + } + return merkle.HashFromByteSlices(commits), nil +} +``` + +Now we can fulfill the second constraint: + +- The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. + + +```go +func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { + ... + // iterate over all of the MsgPayForData transactions and ensure that they + // commitments are subtree roots of the data root. + for _, rawTx := range req.BlockData.Txs { + // iterate through the transactions and check if they are malleated + ... + for _, msg := range tx.GetMsgs() { + if sdk.MsgTypeURL(msg) != types.URLMsgPayForData { + continue + } + + pfd, ok := msg.(*types.MsgPayForData) + if !ok { + app.Logger().Error("Msg type does not match MsgPayForData URL") + continue + } + + if err = pfd.ValidateBasic(); err != nil { + ... + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_REJECT, + } + } + + commitment, err := inclusion.GetCommit(cacher, dah, int(malleatedTx.ShareIndex), shares.MsgSharesUsed(int(pfd.MessageSize))) + if err != nil { + ... + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_REJECT, + } + } + + if !bytes.Equal(pfd.MessageShareCommitment, commitment) { + ... + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_REJECT, + } + } + } + } + ... + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_ACCEPT, + } +} +``` + +Lastly, we also need to check that each valid `MsgPayForData` has a corresponding message, and that there are no unexpected messages. + +- If a `MsgPayForData` is added to the square, then its corresponding message must also be included. +- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). + +```go +func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { + ... + // iterate over all of the MsgPayForData transactions and ensure that they + // commitments are subtree roots of the data root. + commitmentCounter := 0 + for _, rawTx := range req.BlockData.Txs { + // iterate through the transactions and check if they are malleated + ... + for _, msg := range tx.GetMsgs() { + ... + commitmentCounter++ + } + } + + // compare the number of PFDs and messages, if they aren't + // identical, then we already know this block is invalid + if commitmentCounter != len(req.BlockData.Messages.MessagesList) { + ... + return abci.ResponseProcessProposal{ + Result: abci.ResponseProcessProposal_REJECT, + } + } + ... +} +``` + +## Future Improvements + +The current implementation performs many different estimation and calculation steps. It might be possible to amortize these calculations to each transaction, which would make it a lot easier to confidently arrange an optimal block. + ## Status {Deprecated|Proposed|Accepted|Declined} @@ -281,7 +687,8 @@ func estimateSquareSize(txs []*parsedTx, evd core.EvidenceList) (uint64, int) { ### Negative -- Potentially there will be a lot of wasted square space +- There will be more wasted square space +- Adds significant complexity to block creation ### Neutral From 152be10025cf7cd96ee2d55f31054810846a859f Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 31 Aug 2022 22:31:26 -0500 Subject: [PATCH 04/35] linter --- docs/architecture/ADR-003-Non-interactive-defaults.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 949275f7da..ea770e491b 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -365,7 +365,6 @@ If there are too many transactions and messages in the square to fit in the max The simplest approach, and the one taken in the initial implementation, works by prematurely pruning the txs if we estimate that too many shares are being used. While this does work, and fulfills the constraints discussed earlier to create valid blocks, it is suboptimal. Ideally we would be able to identify the most optimal message and transactions to remove and simply remove only those. As mentioned earlier, technically, a single byte difference could change the entire arrangement of the square. Which makes arranging the square with complete confidence difficult not only because we have to follow all of the constraints, but also because of our frequent reliance on variable length length delimiters, and protofuf changing the amount of bytes used depending on the size of ints/uints. - ```go func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { ... @@ -461,8 +460,6 @@ Fortunately, most of the work necessary for non-interactive defaults is encapsul We are already checking the first constraint simply be calculating the data root. The only changes we need to make here are to cache the nmt trees generated when comparing the data root, and then use those cached trees to find the subtree roots necessary to create the data commitments. - - #### Implement the ability to traverse an nmt tree to find subtree roots We need to be able to check for message inclusion using only subtree roots, and in order to do that we have to first know which subtree roots are needed. Given a message's starting position and length, we should be able to calculate that. @@ -588,7 +585,6 @@ Now we can fulfill the second constraint: - The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. - ```go func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { ... From 764fc74c05ce3c19105b83578195c06a29e7485e Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Wed, 31 Aug 2022 22:38:24 -0500 Subject: [PATCH 05/35] remove unused images --- .../assets/increased-ns-4.drawio.png | Bin 46642 -> 0 bytes .../assets/subtreeroot-bold-labeled.drawio.png | Bin 10889 -> 0 bytes docs/architecture/assets/subtreeroot.drawio.png | Bin 9799 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/architecture/assets/increased-ns-4.drawio.png delete mode 100644 docs/architecture/assets/subtreeroot-bold-labeled.drawio.png delete mode 100644 docs/architecture/assets/subtreeroot.drawio.png diff --git a/docs/architecture/assets/increased-ns-4.drawio.png b/docs/architecture/assets/increased-ns-4.drawio.png deleted file mode 100644 index ef5d5e054cc873411be878f0471be428b341a87b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46642 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 RDN+G{M*3!Y?{%D_{|D1`nVA3p diff --git a/docs/architecture/assets/subtreeroot-bold-labeled.drawio.png b/docs/architecture/assets/subtreeroot-bold-labeled.drawio.png deleted file mode 100644 index b87b33dbccd0fe4719fdcb1eb13e52741bfdba06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10889 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 AZtd9k|VZlnx9U!ikR2 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%0DHT(BVcq?n@|E>-2oU z032pPwRj_%X=bn8|B(zEJn2oAXU6sj#RbsC=bB@+dGIHyb%&ET0vvz+$OPw>%dg%u_}^kN7Jh{%n$9B!tmZ+C4leCyT>oJF8)zIzrT6F zaZBDn+MtYrjMeZt_OUSqz-O7r*0hf-9jA`?-2&$Brs+DxQ^T94tU1(&Y)d0a)bXjV zZY7!g!bSDKkw6Q93*d!QnS;wShJ65JF1Huq2V$0esS-9-0=WWWorMDINtN7($Pvq|fD@3q$(pVj0^1~0_+ zt#&GktlxSgj~NMCd3V(41-^ZYaoycoTe|HzBC_l)MBKux8<(A#Bs1_#F-fswq$T6Z zu2IMRNnX-{nVsuQUNci#=`{(icq2WMiv!K3Opm*s^={ufwxMjOx=*IQNvC_hw7_Tx z82@CUBV=SPegUC-qrM+d{m03;;Jw4}ic`1V@_M6s?wcwL;}uFZ8R<4-R~;Q5 z<-fjwNrsTdWRKlG|DmlmSwo=e}mjzp2{xW}D~8mkyvIPjB5tC6sg>vRZXB zd(R=PBmPZ{1?=y3DeYs`DM@&)QQeyn;A&duT#4sB50%Pi3X6|y4qQ2TIAp}puSU$I zNcP4|XD)A(3@g%)OU$)dRWqmGG%4TFyKgv?(`_2{w&VTA6rA23J|s2C&UPexna?=@mqaQ`sv+rmOuId zYt$2(SIUYo;J*n-{C5ori@dsCAlv0y>R-&RHUOUnm7&u?Aj0+2`lU63zBP-Nj~`rk z7NY<5#5O!X*Wlx`yz&GLsm^b|87b8UMFUw}&6I~1E`gp^ z&GH_tY73u3?|naMn|pn1bfXGBv!^UP`@wB5tz9_g>?15NMSLP2OWpYWqx2Q7PG>M& zOJ?AtW-6LG5JG9opZ1z6!bbm5}5_ zKI7p6Kz?1CDmnBLXzXurPFoVlx%1c~yXhDa0`jf0eRM9e=hHYp5mMRDE+X zNGw42;}O+Ucxe#(v@3QcgEv6dSVqRTjI@N|LwE;U_tM>>JU`Cq+T__Wg;Yi`(&%h# z_c2YIebu`~k92M2HPI<(;U=hZwh6YEm%X!Mv#cl}^&Xeo>InlftK`|Np?KmSv>s#*Rq8Aw?njF52TQFz`L9E8&lJ!i!W}o|X zVy~4GNMsjWc@ATQZrFDm-LT2}nnnd$6y$kU(Lt+P6j~CNkh8wgv|NTjaC;a09eON9 ztl(ThxCNd;_eb>h=j&^kj;U^el%maq=Yya`bQz3#iVijgU@8dUgit zk@ADlB@FE3+5W0(&>0(82j@Of?|gNm#;bH7fza|mR`;#zq>$vDsOU#X*(r1d@6X0^ zu@?)aUjTJ+y$L%(U4@O$lEXoSb(G=Z``Y-E-pj{7U-?5?P(f>T!A+IjvOo1R0I^R-kPRs4ng1kLx`@jsr}Eb3cw)a68d^Ug7VS+rmp z-N{X4mA|>I2!0WCGRpq9&5^QFeJ$y9sF0@2ev1Vd+Zk<_BKq>`T;F>M@cwgg<**W@ SPx{X=0KtxITaP`G`u_kc;cWu| From dd0ac52de7aeb1fe26ba8ee7e72848878eac3cf1 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 1 Sep 2022 13:55:36 -0500 Subject: [PATCH 06/35] fix a bunch of wording --- .../ADR-003-Non-interactive-defaults.md | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index ea770e491b..447d38b3b7 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -2,7 +2,7 @@ NOTE: Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs. -The exact approach taken by the initial implementation, however, are certainly up for scrutiny. In this specific case, if there are significant changes proposed, then we might want to implement those improvements in other ADRs/PRs considering that we want to switch to a functioning version of non-interactive defaults as soon as possible. +The exact approach taken by the initial implementation, however, is certainly up for scrutiny. ## Intro @@ -14,19 +14,21 @@ While this functions as a message inclusion check, the light client has to assum > **All share commitments included in `MsgPayForData` must consist only of subtree roots of the data square.** -The main issue with that requirement is that it requires the users to know the relevant subtree roots before they sign, which is problematic considering that is the block is not organized perfectly, the subtree roots will include data unknown to the user at the time of signing. +The main issue with that requirement is that users must know the relevant subtree roots before they sign, which is problematic considering that is the block is not organized perfectly, the subtree roots will include data unknown to the user at the time of signing. -To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional message layout rules that allow for commitments to messages to consist entirely of sub tree roots of the data root, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: MODIFIED FROM THE SPEC +To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional **default but optional** message layout rules that enables the user to follow the above block validity rule, while also not interacting with a block producer. Commitments to messages can consist entirely of sub tree roots of the data hash, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: THE STATEMENT BELOW IS MODIFIED FROM THE SPEC > **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** +Below illustrates how we can break a message up into two different subtree roots, root `A` for first four shares, and root `B` consisting of the last two shares. We can then create a commitment out of any number of subtree roots by creating a merkle root of those commitments. + ![Subtree root commitment](./assets/subtree-root.png "Subtree Root based commitments") > **If the messages are larger than k, then they must start on a new row.** ![Multi row share commitment](./assets/multirow.png "Subtree Root based commitments") -If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. Below illustrates how we can break a message up into two different subtree roots, the first for first four shares, the second consisting of the last two shares. +If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of the namespace of the message before it, with all zeros for data. @@ -37,7 +39,7 @@ Below is an example block that has been filled using the non-interactive default ![example](./assets/example-full-block.png "example") -Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. +Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. This is important to reduce the trust assumptions made by light clients. ## Decision @@ -47,11 +49,9 @@ While there certainly can be some decisions here, whether or not we begin follow ## Alternative Designs -As the first note of this document describes, the purpose of this document is not really to decide wether or not we're implementing non-interactive defaults, that has already been decided. While the exact details of the implementation are certainly up for scrutiny, those should be discussed in a different ADR - -While all commitments signed over must only consist of subtree roots, its worth noting that non-interactive defaults are just that, defaults! It's entirely possible that block producers use some mechanism to notify the signer of the commitments that they must sign over, or even that the block producers are signing paying for the inclusion of the message on behalf of the users. This would render the non-interactive defaults, and the padding accompanied by them, to not be necessary. Other solutions are not mutually exclusive to non-interactive defaults, and do not even have to be built by the core team, so covering those solutions in a more in depth way is outside the scope of this ADR. +While all commitments signed over must only consist of subtree roots, its worth noting that non-interactive defaults are just that, defaults! It's entirely possible that block producers use some mechanism to notify the signer of the commitments that they must sign over, or even that the block producers are signing the transactions paying for the inclusion of the message on behalf of the users. This would render the non-interactive defaults, and the padding accompanied by them, to not be necessary. Other solutions are not mutually exclusive to non-interactive defaults, and do not even have to be built by the core team, so covering those solutions in a more in depth way is outside the scope of this ADR. -However, the default implementation of non-interative defaults is within the scope of this ADR. Whatever design we use ultimately needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults, and we still need to be able to check for message inclusion using subtree roots. +However, the default implementation of non-interative defaults is within the scope of this ADR. Whatever design we use ultimately needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults. Again, this not change the requirement that all share commitments signed over in PFDs consist only of subtree roots. ## Detailed Design @@ -60,13 +60,13 @@ To recap the default constraints of arranging a square: - All messages must be ordered lexicographically by namespace. - The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. -- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- There must not be a message without a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). - Transactions with higher fees should be prioritized by default. - Ideally, the square should be filled as optimally as possible. For squares that are smaller than the max squaresize, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place. -Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual computation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Calculating the exact number of bytes used is further complicated by the order of the steps due to our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. +Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual computation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Calculating the exact number of bytes used is further complicated by the order of the steps due and our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. ![extra message that can't fit](./assets/extra-message-that-doesnt-fit.png "extra message") ![fit the extra message by removing a tx](./assets/fit-extra-msg-byremoving-tx.png "extra message") @@ -82,7 +82,7 @@ To meet the above constraints, there are multiple refactors required. ### Add metadata to wrapped transactions [#819](https://github.com/celestiaorg/celestia-core/pull/819) -In order to check for message inclusion, create message inclusion fraud proofs, split the block data into squares, and not force non-interactive defaults for every square, we have to connect a `MsgPayForData` transaction to its corresponding message. Since users cannot know this ahead of time, block producers have to add this information as metadata before the transaction gets included in the block. +In order to check for message inclusion, create message inclusion fraud proofs, split the block data into squares, and not force non-interactive defaults for every square, we have to connect a `MsgPayForData` transaction to its corresponding message by adding the index of the share that the message starts on as metadata. Since users cannot know this ahead of time, block producers have to add this metadata before the transaction gets included in the block. We are already wrapping/unwrapping malleated transactions, so including the `share_index` as metadata using the current code is essentially as simple as adding the `share_index` to the struct. Transactions are unwrapped selectively by using a [`MalleatedTxDecoder`](https://github.com/celestiaorg/celestia-app/blob/5ac236fb1dab6628e98a505269f295c18e150b27/app/encoding/malleated_tx_decoder.go#L8-L15) or by using the [`UnwrapMalleatedTx`](https://github.com/celestiaorg/celestia-core/blob/212901fcfc0f5a095683b1836ea9e890cc952dc7/types/tx.go#L214-L237) function. @@ -98,9 +98,9 @@ uint32 share_index = 3; Our encoding scheme now has to actually use the metadata added to wrapped transactions. -Note: In order to properly test the new encoding scheme, we have to perform identical if not very similar application logic to that in `PrepareProposal` for this reason, we initially wanted to move the share encoding/decoding logic to the app instead of core. There were some other quality of life improvements that were also added during this refactor that are technically unrelated to these changes. +Note: In order to properly test the new encoding scheme, we have to perform identical if not very similar application logic to that in `PrepareProposal`, for this reason, we initially wanted to move the share encoding/decoding logic to the app instead of core. There were some other quality of life improvements that were also added during this refactor that are technically unrelated to these changes. -We currently utilize a struct to store the state needed for lazily writing message shares (todo: possibly change this name). Here we add a method to it that allows for us to write namespaced padded shares. +We currently utilize a struct to store the state needed for lazily writing message shares. Here we add a method to it that allows for us to write namespaced padded shares. ```go // MessageShareSplitter lazily splits messages into shares that will eventually be @@ -150,7 +150,7 @@ When parsing the message shares, we can simply ignore these added namespaced pad ### Implement the non-interactive default logic -recall our non-interactive default rule: +recall our non-interactive default message layout rule: > **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** @@ -205,11 +205,11 @@ We can now use this function in many places, such as when we estimate the square ### Refactor `PrepareProposal` -From a very high level perspective `PrepareProposal` stays mostly the same. We need to estimate the square size accurately enough to pick a square size so that we can malleate the transactions that are given to us by tendermint, then arrange messages in a square. However, recall the constraints and issues described at the top of this section. Technically, the addition or removal of a single byte can change the entire arrangement of the square. Knowing, or at least being able to estimate how many shares/bytes are used is critical to finding an optimal solution to arranging the square yet the constraints themselves along with our frequent use of variable length encoding techniques make estimating much more complicated. +From a very high level perspective `PrepareProposal` stays mostly the same. We need to estimate the square size accurately enough to pick a square size so that we can malleate the transactions that are given to us by tendermint and arrange those messages in a square. However, recall the constraints and issues described at the top of this section. Technically, the addition or removal of a single byte can change the entire arrangement of the square. Knowing, or at least being able to estimate, how many shares/bytes are used is critical to finding an optimal solution to arranging the square. Yet the constraints themselves along with our frequent use of variable length encoding techniques make estimating much more complicated. -While messages must be ordered lexicographically, we also have to order transactions by their fees and ensure that each message is added atomically with its corresponding `MsgPayForData` transaction. Also, malleated transactions exist alongside normal transactions, the former of which we have to add **variable sized** metadata to only _after_ we know the starting location of each message. All while following the non-interactive defaults, both of which make it difficult to accurately estimate the number of shares or bytes used. +While messages must be ordered lexicographically, we also have to order transactions by their fees and ensure that each message is added atomically with its corresponding `MsgPayForData` transaction. Also, malleated transactions exist alongside normal transactions, the former of which we have to add **variable sized** metadata to only _after_ we know the starting location of each message. All while following the non-interactive defaults. -Below is the lightly summarized code for `PrepareProposal` that we can use a high level map of what we're doing to arrange the block data into a square. +Below is the lightly summarized code for `PrepareProposal` that we can use as a high level map of how we're going to arrange the block data into a square. ```go // PrepareProposal fulfills the celestia-core version of the ABCI interface by @@ -304,7 +304,7 @@ func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePr #### Square Estimation -Using some of the non-interactive defaults code above, we can quickly calculate the size of each reserved namespace shares using the parsed transactions. As discussed in the docs of this function, the goal here is not necessarily to get a perfect count of the shares that are being used, but we do need to know roughly what square size is needed. When estimating, we should round up in square size. +Using some of the non-interactive defaults code above, we can quickly calculate the number of shares required by each type of block data. As discussed in the docs of this function, the goal here is not necessarily to get a perfect count of the shares that are being used, but we do need to know roughly what square size is needed. When estimating, we should round up in square size. ```go // FitsInSquare uses the non interactive default rules to see if messages of @@ -363,7 +363,7 @@ func estimateSquareSize(txs []*parsedTx, evd core.EvidenceList) (uint64, int) { If there are too many transactions and messages in the square to fit in the max square size, then we have to remove them from the block. This can be complicated, as by default we want to prioritzie transactions that have higher fees, but removing a low fee transaction doesn't always result in using less shares. -The simplest approach, and the one taken in the initial implementation, works by prematurely pruning the txs if we estimate that too many shares are being used. While this does work, and fulfills the constraints discussed earlier to create valid blocks, it is suboptimal. Ideally we would be able to identify the most optimal message and transactions to remove and simply remove only those. As mentioned earlier, technically, a single byte difference could change the entire arrangement of the square. Which makes arranging the square with complete confidence difficult not only because we have to follow all of the constraints, but also because of our frequent reliance on variable length length delimiters, and protofuf changing the amount of bytes used depending on the size of ints/uints. +The simplest approach, and the one taken in the initial implementation, works by prematurely pruning the txs if we estimate that too many shares are being used. While this does work, and fulfills the constraints discussed earlier to create valid blocks, it is suboptimal. Ideally we would be able to identify the most optimal message and transactions to remove and then simply remove only those. As mentioned earlier, technically, a single byte difference could change the entire arrangement of the square. This makes arranging the square with complete confidence difficult not only because we have to follow all of the constraints, but also because of our frequent reliance on variable length length delimiters, and protofuf changing the amount of bytes used depending on the size of ints/uints. ```go func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { @@ -379,7 +379,7 @@ func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePr #### Malleation -Due to the use of the `parsedTxs` data structure, we can now abstract the malleation process entirely. Whereas before it was hard coded into the share proprietary proposal share splitting logic. +Due to the use of the `parsedTxs` data structure, we can now abstract the malleation process entirely, whereas before it was hard coded into the share proprietary proposal share splitting logic. ```go func (p *parsedTx) malleate(txConf client.TxConfig, squareSize uint64) error { @@ -456,7 +456,7 @@ Fortunately, most of the work necessary for non-interactive defaults is encapsul - All messages must be ordered lexicographically by namespace. - The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. -- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- There must not be a message without a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). We are already checking the first constraint simply be calculating the data root. The only changes we need to make here are to cache the nmt trees generated when comparing the data root, and then use those cached trees to find the subtree roots necessary to create the data commitments. @@ -637,7 +637,7 @@ func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponsePr Lastly, we also need to check that each valid `MsgPayForData` has a corresponding message, and that there are no unexpected messages. - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. -- There must not be a message with a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- There must not be a message without a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). ```go func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { From 12afde0dbf6f4430fd486c1b36dd2c2881009f30 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 1 Sep 2022 16:45:33 -0500 Subject: [PATCH 07/35] better wording Co-authored-by: Rootul Patel --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 447d38b3b7..c6b5e937c1 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -30,7 +30,7 @@ Below illustrates how we can break a message up into two different subtree roots If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. -In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of the namespace of the message before it, with all zeros for data. +In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of shares with the namespace of the message before it, with all zeros for data. ![Before using the non-interactive defaults](./assets/before.png "Before requiring that all commits consist of subtree roots") ![after](./assets/after.png "After requiring that all commits consist of subtree roots") From e95584ca86360e6fcc7b22926f0f189475c2beef Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 1 Sep 2022 16:46:23 -0500 Subject: [PATCH 08/35] remove todo --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index c6b5e937c1..fc5a86ceb1 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -10,7 +10,7 @@ pls see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/ Currently, when checking for message inclusion, validators recreate the share commitment from the messages in the block and compare those with what are signed over in the `MsgPayForData` transactions also in that block. If any commitment is not found in one of the PFD transactions, or if there is a commitment that doesn't have a corresponding message, then they reject that block. -While this functions as a message inclusion check, the light client has to assume that 2/3's of the voting power is honest in order to be assured that both the messages they are interested in and the rest of the messages paid for in that block are actually included. In order to have this property, we need a block (or tx? pls halp reviewers) validity rule where: +While this functions as a message inclusion check, the light client has to assume that 2/3's of the voting power is honest in order to be assured that both the messages they are interested in and the rest of the messages paid for in that block are actually included. In order to have this property, we need a block validity rule where: > **All share commitments included in `MsgPayForData` must consist only of subtree roots of the data square.** From 813400a50fe0a57b318b2c09e3c030d1e374a909 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Thu, 1 Sep 2022 16:48:53 -0500 Subject: [PATCH 09/35] missing word Co-authored-by: Rootul Patel --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 447d38b3b7..43bb351a07 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -45,7 +45,7 @@ Not only does doing this allow for easy trust minimized message inclusion checks TBD -While there certainly can be some decisions here, whether or not we begin following the non-interactive defaults isn't really the goal of this ADR. Please the note at the top of this document. +While there certainly can be some decisions here, whether or not we begin following the non-interactive defaults isn't really the goal of this ADR. Please see the note at the top of this document. ## Alternative Designs From d370eeb7f7b8c9a3b19a490eb2a3fbf88a3bd991 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 1 Sep 2022 16:50:46 -0500 Subject: [PATCH 10/35] spelling Co-authored-by: Rootul Patel --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index fc5a86ceb1..4905315cb2 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -363,7 +363,7 @@ func estimateSquareSize(txs []*parsedTx, evd core.EvidenceList) (uint64, int) { If there are too many transactions and messages in the square to fit in the max square size, then we have to remove them from the block. This can be complicated, as by default we want to prioritzie transactions that have higher fees, but removing a low fee transaction doesn't always result in using less shares. -The simplest approach, and the one taken in the initial implementation, works by prematurely pruning the txs if we estimate that too many shares are being used. While this does work, and fulfills the constraints discussed earlier to create valid blocks, it is suboptimal. Ideally we would be able to identify the most optimal message and transactions to remove and then simply remove only those. As mentioned earlier, technically, a single byte difference could change the entire arrangement of the square. This makes arranging the square with complete confidence difficult not only because we have to follow all of the constraints, but also because of our frequent reliance on variable length length delimiters, and protofuf changing the amount of bytes used depending on the size of ints/uints. +The simplest approach, and the one taken in the initial implementation, works by prematurely pruning the txs if we estimate that too many shares are being used. While this does work, and fulfills the constraints discussed earlier to create valid blocks, it is suboptimal. Ideally we would be able to identify the most optimal message and transactions to remove and then simply remove only those. As mentioned earlier, technically, a single byte difference could change the entire arrangement of the square. This makes arranging the square with complete confidence difficult not only because we have to follow all of the constraints, but also because of our frequent reliance on variable length length delimiters, and protobuf changing the amount of bytes used depending on the size of ints/uints. ```go func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { From a161fbbfccf371df1f246cbcd0c8b299014849c7 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 1 Sep 2022 22:40:40 -0500 Subject: [PATCH 11/35] fix word Co-authored-by: Rootul Patel --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 7ec301f1e2..eadb75e27c 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -14,7 +14,7 @@ While this functions as a message inclusion check, the light client has to assum > **All share commitments included in `MsgPayForData` must consist only of subtree roots of the data square.** -The main issue with that requirement is that users must know the relevant subtree roots before they sign, which is problematic considering that is the block is not organized perfectly, the subtree roots will include data unknown to the user at the time of signing. +The main issue with that requirement is that users must know the relevant subtree roots before they sign, which is problematic considering that if the block is not organized perfectly, the subtree roots will include data unknown to the user at the time of signing. To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional **default but optional** message layout rules that enables the user to follow the above block validity rule, while also not interacting with a block producer. Commitments to messages can consist entirely of sub tree roots of the data hash, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: THE STATEMENT BELOW IS MODIFIED FROM THE SPEC From 27ee1dac22be7498ebfb87be85c7cd4718a4d56e Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Thu, 1 Sep 2022 23:13:40 -0500 Subject: [PATCH 12/35] be more explicit with splitting shares api Co-authored-by: Rootul Patel --- docs/architecture/ADR-003-Non-interactive-defaults.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index eadb75e27c..28122d2985 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -130,14 +130,14 @@ func (msw *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { Now we simply combine this new functionality with the `share_index`s described above, and we can properly split and pad messages when needed. Note, the below implementation allows for `nil` to be passed as indexes. This is important, as it allows the same implementation to be used in the cases where we don't want to split messages using wrapped transactions, such as supporting older networks or when users create commitments to sign over for `MsgWirePayForData` ```go -func SplitMessages(cursor int, indexes []uint32, msgs []coretypes.Message) ([][]byte, error) { - if indexes != nil && len(indexes) != len(msgs) { +func SplitMessages(cursor int, indexes []uint32, msgs []coretypes.Message, useShareIndexes bool) ([][]byte, error) { + if len(indexes) != len(msgs) { return nil, ErrIncorrectNumberOfIndexes } writer := NewMessageShareSplitter() for i, msg := range msgs { writer.Write(msg) - if indexes != nil && len(indexes) > i+1 { + if useShareIndexes && len(indexes) > i+1 { paddedShareCount := int(indexes[i+1]) - (writer.Count() + cursor) writer.WriteNamespacedPaddedShares(paddedShareCount) } From a74e1ecdce5789196c7696f22e568959b0e94039 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Sun, 4 Sep 2022 14:11:27 -0500 Subject: [PATCH 13/35] move comment to emphasize Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 28122d2985..eca1904c3a 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -16,7 +16,9 @@ While this functions as a message inclusion check, the light client has to assum The main issue with that requirement is that users must know the relevant subtree roots before they sign, which is problematic considering that if the block is not organized perfectly, the subtree roots will include data unknown to the user at the time of signing. -To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional **default but optional** message layout rules that enables the user to follow the above block validity rule, while also not interacting with a block producer. Commitments to messages can consist entirely of sub tree roots of the data hash, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). NOTE: THE STATEMENT BELOW IS MODIFIED FROM THE SPEC +To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional **default but optional** message layout rules that enables the user to follow the above block validity rule, while also not interacting with a block producer. Commitments to messages can consist entirely of sub tree roots of the data hash, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). + +NOTE: THE STATEMENT BELOW IS MODIFIED FROM THE SPEC > **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** From 502ba937e23555b77fc1bea016cfb26ebc0f24f0 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Sun, 4 Sep 2022 14:13:37 -0500 Subject: [PATCH 14/35] add word Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index eca1904c3a..84054fef4b 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -53,7 +53,7 @@ While there certainly can be some decisions here, whether or not we begin follow While all commitments signed over must only consist of subtree roots, its worth noting that non-interactive defaults are just that, defaults! It's entirely possible that block producers use some mechanism to notify the signer of the commitments that they must sign over, or even that the block producers are signing the transactions paying for the inclusion of the message on behalf of the users. This would render the non-interactive defaults, and the padding accompanied by them, to not be necessary. Other solutions are not mutually exclusive to non-interactive defaults, and do not even have to be built by the core team, so covering those solutions in a more in depth way is outside the scope of this ADR. -However, the default implementation of non-interative defaults is within the scope of this ADR. Whatever design we use ultimately needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults. Again, this not change the requirement that all share commitments signed over in PFDs consist only of subtree roots. +However, the default implementation of non-interative defaults is within the scope of this ADR. Whatever design we use ultimately needs to support not using the non-interactive defaults. Meaning we should be able to encode block data into a square even if the messages are not arranged according to the non-interactive defaults. Again, this does not change the requirement that all share commitments signed over in PFDs consist only of subtree roots. ## Detailed Design From edfac9e891c07246ae063cc3cd4da2240958c44c Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Sun, 4 Sep 2022 14:19:47 -0500 Subject: [PATCH 15/35] add comment explaining the namespaces and messages used in the diagram Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 84054fef4b..b35c1f506a 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -41,6 +41,11 @@ Below is an example block that has been filled using the non-interactive default ![example](./assets/example-full-block.png "example") +- `ns = 1`: The first namespace is put in the beginning of the messages space. +- `ns = 2`: Starting at the largest power of 2 that is not (strictly) larger than the message length or `k`. +- `ns = 3`: Message spanning multiple rows. So, it will be at the beginning of a new row. +- `ns = 4`: Starting at the largest power of 2 that is not (strictly) larger than the message length or `k`. + Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. This is important to reduce the trust assumptions made by light clients. ## Decision From c91e1697cfaba287250beba0413a18adde44a152 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Sun, 4 Sep 2022 14:28:54 -0500 Subject: [PATCH 16/35] user merkle mountain range to describe subtree root commitment Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index b35c1f506a..11b90b0bed 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -22,7 +22,7 @@ NOTE: THE STATEMENT BELOW IS MODIFIED FROM THE SPEC > **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** -Below illustrates how we can break a message up into two different subtree roots, root `A` for first four shares, and root `B` consisting of the last two shares. We can then create a commitment out of any number of subtree roots by creating a merkle root of those commitments. +Below illustrates how we can break a message up into two different subtree roots, following a [Merkle Mountain Range](https://docs.grin.mw/wiki/chain-state/merkle-mountain-range/) structure, i.e. root `A` for first four shares, and root `B` consisting of the last two shares. We can then create a commitment out of any number of subtree roots by creating a merkle root of those commitments. ![Subtree root commitment](./assets/subtree-root.png "Subtree Root based commitments") From 7dc68b252da5ca9807f6c8861baf5a35036f7e44 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Sun, 4 Sep 2022 14:31:35 -0500 Subject: [PATCH 17/35] msw -> mss Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index b35c1f506a..c6fb9e4321 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -121,16 +121,16 @@ type MessageShareSplitter struct { // WriteNamespacedPaddedShares adds empty shares using the namespace of the last written share. // This is useful to follow the message layout rules. It assumes that at least // one share has already been written, if not it panics. -func (msw *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { - if len(msw.shares) == 0 { +func (mss *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { + if len(mss.shares) == 0 { panic("Cannot write empty namespaced shares on an empty MessageShareSplitter") } if count == 0 { return } - lastMessage := msw.shares[len(msw.shares)-1] - msw.shares = append(msw.shares, namespacedPaddedShares(lastMessage[0].ID, count)) - msw.count += count + lastMessage := mss.shares[len(mss.shares)-1] + mss.shares = append(mss.shares, namespacedPaddedShares(lastMessage[0].ID, count)) + mss.count += count } ``` From c8959f8a25bb5a29f9417d5b37b1f0377afae70f Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Sun, 4 Sep 2022 14:49:38 -0500 Subject: [PATCH 18/35] update wording and implementation to reflect the usage of --- docs/architecture/ADR-003-Non-interactive-defaults.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index b8ac53e665..9c3f83f67f 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -134,11 +134,11 @@ func (mss *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { } ``` -Now we simply combine this new functionality with the `share_index`s described above, and we can properly split and pad messages when needed. Note, the below implementation allows for `nil` to be passed as indexes. This is important, as it allows the same implementation to be used in the cases where we don't want to split messages using wrapped transactions, such as supporting older networks or when users create commitments to sign over for `MsgWirePayForData` +Now we simply combine this new functionality with the `share_index`s described above, and we can properly split and pad messages when needed. Note, the below implementation allows indexes to not be used. This is important, as it allows the same implementation to be used in the cases where we don't want to split messages using wrapped transactions, such as supporting older networks or when users create commitments to sign over for `MsgWirePayForData` ```go func SplitMessages(cursor int, indexes []uint32, msgs []coretypes.Message, useShareIndexes bool) ([][]byte, error) { - if len(indexes) != len(msgs) { + if useShareIndexes && len(indexes) != len(msgs) { return nil, ErrIncorrectNumberOfIndexes } writer := NewMessageShareSplitter() From 66e811b50229a0e6496d576a3b3bf5b412ae78a9 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Sun, 4 Sep 2022 15:07:08 -0500 Subject: [PATCH 19/35] wording Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 9c3f83f67f..5ae7f02737 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -595,7 +595,7 @@ Now we can fulfill the second constraint: ```go func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { ... - // iterate over all of the MsgPayForData transactions and ensure that they + // iterate over all of the MsgPayForData transactions and ensure that their // commitments are subtree roots of the data root. for _, rawTx := range req.BlockData.Txs { // iterate through the transactions and check if they are malleated From 3373aba7b5f350df4804a41bc8c01485f6c6bb0c Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Sun, 4 Sep 2022 15:15:47 -0500 Subject: [PATCH 20/35] Apply suggestions from code review Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 5ae7f02737..195cc251eb 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -91,7 +91,7 @@ To meet the above constraints, there are multiple refactors required. In order to check for message inclusion, create message inclusion fraud proofs, split the block data into squares, and not force non-interactive defaults for every square, we have to connect a `MsgPayForData` transaction to its corresponding message by adding the index of the share that the message starts on as metadata. Since users cannot know this ahead of time, block producers have to add this metadata before the transaction gets included in the block. -We are already wrapping/unwrapping malleated transactions, so including the `share_index` as metadata using the current code is essentially as simple as adding the `share_index` to the struct. Transactions are unwrapped selectively by using a [`MalleatedTxDecoder`](https://github.com/celestiaorg/celestia-app/blob/5ac236fb1dab6628e98a505269f295c18e150b27/app/encoding/malleated_tx_decoder.go#L8-L15) or by using the [`UnwrapMalleatedTx`](https://github.com/celestiaorg/celestia-core/blob/212901fcfc0f5a095683b1836ea9e890cc952dc7/types/tx.go#L214-L237) function. +We are already wrapping/unwrapping malleated transactions, so including the `share_index` as metadata using the current code is essentially as simple as adding the `share_index` to the struct. Transactions are unwrapped selectively by using a [`MalleatedTxDecoder(...)`](https://github.com/celestiaorg/celestia-app/blob/5ac236fb1dab6628e98a505269f295c18e150b27/app/encoding/malleated_tx_decoder.go#L8-L15) or by using the [`UnwrapMalleatedTx(...)`](https://github.com/celestiaorg/celestia-core/blob/212901fcfc0f5a095683b1836ea9e890cc952dc7/types/tx.go#L214-L237) function. ```proto message MalleatedTx { @@ -540,7 +540,7 @@ func (strc *subTreeRootCacher) Visit(hash []byte, children ...[]byte) { type EDSSubTreeRootCacher struct { caches []*subTreeRootCacher squareSize uint64 - // counter is used to ignore columns NOTE: this is a leaky abstraction that + // counter is used to ignore columns. NOTE: this is a leaky abstraction that // we make because rsmt2d is used to generate the roots for us, so we have // to assume that it will generate a row root every other tree constructed. // This is also one of the reasons this implementation is not thread safe. @@ -679,7 +679,7 @@ The current implementation performs many different estimation and calculation st ## Status -{Deprecated|Proposed|Accepted|Declined} +Accepted ## Consequences From 98f10e16573589a6d2d42276b24593367991c7c4 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Tue, 6 Sep 2022 07:31:29 -0500 Subject: [PATCH 21/35] change var name of nextAlignedPowerOfTwo --- docs/architecture/ADR-003-Non-interactive-defaults.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 28122d2985..ca84bdeb5b 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -164,15 +164,15 @@ The key to arranging the square into non-interactive defaults is calculating the // see specs for further details. Assumes that cursor < k, all args are non // negative, and that k is a power of two. // https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules -func NextAlignedPowerOfTwo(cursor, msgLen, k int) (int, bool) { +func NextAlignedPowerOfTwo(cursor, msgLen, squareSize int) (int, bool) { // if we're starting at the beginning of the row, then return as there are // no cases where we don't start at 0. - if cursor == 0 || cursor%k == 0 { + if cursor == 0 || cursor%squareSize == 0 { return cursor, true } nextLowest := nextLowestPowerOfTwo(msgLen) - endOfCurrentRow := ((cursor / k) + 1) * k + endOfCurrentRow := ((cursor / squareSize) + 1) * squareSize cursor = roundUpBy(cursor, nextLowest) switch { // the entire message fits in this row From 70f62c6c3ee519e0fa25a12719915f41362b5e2b Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Tue, 6 Sep 2022 07:34:48 -0500 Subject: [PATCH 22/35] change var name --- docs/architecture/ADR-003-Non-interactive-defaults.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 953e800432..9c9a46c639 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -121,16 +121,16 @@ type MessageShareSplitter struct { // WriteNamespacedPaddedShares adds empty shares using the namespace of the last written share. // This is useful to follow the message layout rules. It assumes that at least // one share has already been written, if not it panics. -func (mss *MessageShareSplitter) WriteNamespacedPaddedShares(count int) { +func (mss *MessageShareSplitter) WriteNamespacedPaddedShares(paddedShares int) { if len(mss.shares) == 0 { panic("Cannot write empty namespaced shares on an empty MessageShareSplitter") } - if count == 0 { + if paddedShares == 0 { return } lastMessage := mss.shares[len(mss.shares)-1] - mss.shares = append(mss.shares, namespacedPaddedShares(lastMessage[0].ID, count)) - mss.count += count + mss.shares = append(mss.shares, namespacedPaddedShares(lastMessage[0].ID, paddedShares)) + mss.count += paddedShares } ``` From 63b0ff3671e20e397b951f3ff82a93d3e36e84c6 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Tue, 6 Sep 2022 13:56:19 -0500 Subject: [PATCH 23/35] remove strictly from comments Co-authored-by: CHAMI Rachid --- docs/architecture/ADR-003-Non-interactive-defaults.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 9c9a46c639..7567a1671c 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -42,9 +42,9 @@ Below is an example block that has been filled using the non-interactive default ![example](./assets/example-full-block.png "example") - `ns = 1`: The first namespace is put in the beginning of the messages space. -- `ns = 2`: Starting at the largest power of 2 that is not (strictly) larger than the message length or `k`. +- `ns = 2`: Starting at the largest power of 2 that is not larger than the message length or `k`. - `ns = 3`: Message spanning multiple rows. So, it will be at the beginning of a new row. -- `ns = 4`: Starting at the largest power of 2 that is not (strictly) larger than the message length or `k`. +- `ns = 4`: Starting at the largest power of 2 that is not larger than the message length or `k`. Not only does doing this allow for easy trust minimized message inclusion checks for specific messages by light clients, but also allows for the creation of message inclusion fraud proofs for all messages in the block. This is important to reduce the trust assumptions made by light clients. From 01b30f005f77053a18535683896cd2e08a4248da Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Fri, 23 Sep 2022 06:36:05 -0500 Subject: [PATCH 24/35] fix: typo Co-authored-by: John Adler --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 7567a1671c..5de41788a2 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -71,7 +71,7 @@ To recap the default constraints of arranging a square: - Transactions with higher fees should be prioritized by default. - Ideally, the square should be filled as optimally as possible. -For squares that are smaller than the max squaresize, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place. +For squares that are smaller than the max square size, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place. Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual computation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Calculating the exact number of bytes used is further complicated by the order of the steps due and our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. From c162833a9b0b5dc4478aad4a7b6970505f1d8c35 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:10:14 -0500 Subject: [PATCH 25/35] fix: pls -> please --- docs/architecture/ADR-003-Non-interactive-defaults.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 9c9a46c639..43004b2b33 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -1,12 +1,13 @@ # ADR 003: Non-interactive Defaults, Wrapped Transactions, and Subtree Root Message Inclusion Checks -NOTE: Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs. +>Note +>Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs. The exact approach taken by the initial implementation, however, is certainly up for scrutiny. ## Intro -pls see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md), from which this ADR paraphrases heavily. +please see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md), from which this ADR paraphrases heavily. Currently, when checking for message inclusion, validators recreate the share commitment from the messages in the block and compare those with what are signed over in the `MsgPayForData` transactions also in that block. If any commitment is not found in one of the PFD transactions, or if there is a commitment that doesn't have a corresponding message, then they reject that block. @@ -167,7 +168,7 @@ The key to arranging the square into non-interactive defaults is calculating the // NextAlignedPowerOfTwo calculates the next index in a row that is an aligned // power of two and returns false if the entire the msg cannot fit on the given // row at the next aligned power of two. An aligned power of two means that the -// largest power of two that fits entirely in the msg or the square size. pls +// largest power of two that fits entirely in the msg or the square size. please // see specs for further details. Assumes that cursor < k, all args are non // negative, and that k is a power of two. // https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules From e8842c8457397e36bd74e78230c5c79724ed89db Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:14:05 -0500 Subject: [PATCH 26/35] fix: better wording Co-authored-by: John Adler --- docs/architecture/ADR-003-Non-interactive-defaults.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 929f0ebc44..d108082d31 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -1,7 +1,7 @@ # ADR 003: Non-interactive Defaults, Wrapped Transactions, and Subtree Root Message Inclusion Checks ->Note ->Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs. +> **Note** +> Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs. The exact approach taken by the initial implementation, however, is certainly up for scrutiny. @@ -31,7 +31,7 @@ Below illustrates how we can break a message up into two different subtree roots ![Multi row share commitment](./assets/multirow.png "Subtree Root based commitments") -If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. +If we follow this rule, we can always create a commitment to subtree roots of the data root, that commit to the data. In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of shares with the namespace of the message before it, with all zeros for data. From 0d22a5358a7e01340ed984fc57369848766edd23 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Fri, 23 Sep 2022 14:14:53 -0500 Subject: [PATCH 27/35] fix: point to figure in comment Co-authored-by: John Adler --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 5de41788a2..3b29b4b86c 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -32,7 +32,7 @@ Below illustrates how we can break a message up into two different subtree roots If we can follow these rules, we can always create a commitment to the data that is a subtree root of the data root while only knowing the data in that message. -In practice this usually means that we end up adding padding between messages (zig-zag hatched share) to ensure that each message is starting at an "aligned power of two". Padding consists of shares with the namespace of the message before it, with all zeros for data. +In practice this usually means that we end up adding padding between messages (zig-zag hatched shares in the figure below) to ensure that each message is starting at an "aligned power of two". Padding consists of shares with the namespace of the message before it, with all zeros for data. ![Before using the non-interactive defaults](./assets/before.png "Before requiring that all commits consist of subtree roots") ![after](./assets/after.png "After requiring that all commits consist of subtree roots") From ccea1f55104789af1bdf5573e503cc060183e069 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:16:28 -0500 Subject: [PATCH 28/35] fix: remove redudundant word "ideally" Co-authored-by: John Adler --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index d108082d31..9224530a14 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -70,7 +70,7 @@ To recap the default constraints of arranging a square: - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. - There must not be a message without a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). - Transactions with higher fees should be prioritized by default. -- Ideally, the square should be filled as optimally as possible. +- The square should be filled as optimally as possible. For squares that are smaller than the max square size, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place. From e3f9831e099b1510a711c7ddfb42dca2f150731e Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:18:42 -0500 Subject: [PATCH 29/35] fix: better wording --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 9224530a14..05345e9156 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -74,7 +74,7 @@ To recap the default constraints of arranging a square: For squares that are smaller than the max square size, the exact approach is much less important. This is because if we can't fit all of the transactions in a square, then by default we shouldn't be using that square size in the first place. -Arranging the messages in the block to maximize for fees and optimize square space is an NP-hard problem. While the actual computation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Calculating the exact number of bytes used is further complicated by the order of the steps due and our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. +Arranging the messages in the block to maximize for fees and optimize square space is a difficult problem that is similar to the ["Bin packing problem"](https://en.wikipedia.org/wiki/Bin_packing_problem). While the actual computation of the number of shares could be cached to an extent, each change to the square potentially affects the rest of the messages in the square. The only way to know for certain is to calculate the number of shares used. Calculating the exact number of bytes used is further complicated by the order of the steps due and our rampant use of varints, both in our encoding scheme and protobuf's. The example below shows how removing a single share (from the transactions in this case) could change the rest of the square and allow for a message that otherwise would not fit. ![extra message that can't fit](./assets/extra-message-that-doesnt-fit.png "extra message") ![fit the extra message by removing a tx](./assets/fit-extra-msg-byremoving-tx.png "extra message") From e706becb357c3042f8ed3971b17cccf26def1dd7 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:21:42 -0500 Subject: [PATCH 30/35] fix: remove statement for reviewers Co-authored-by: Ismail Khoffi --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index ca7f147014..f12ef3e2b6 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -19,8 +19,6 @@ The main issue with that requirement is that users must know the relevant subtre To fix this, the spec outlines the “non-interactive default rules”. These involve a few additional **default but optional** message layout rules that enables the user to follow the above block validity rule, while also not interacting with a block producer. Commitments to messages can consist entirely of sub tree roots of the data hash, and for those sub tree roots to be generated only from the message itself (so that the user can sign something “non-interactively”). -NOTE: THE STATEMENT BELOW IS MODIFIED FROM THE SPEC - > **Messages must begin at a location aligned with the largest power of 2 that is not larger than the message length or k.** Below illustrates how we can break a message up into two different subtree roots, following a [Merkle Mountain Range](https://docs.grin.mw/wiki/chain-state/merkle-mountain-range/) structure, i.e. root `A` for first four shares, and root `B` consisting of the last two shares. We can then create a commitment out of any number of subtree roots by creating a merkle root of those commitments. From 703384a67328574b50c5cd7e4e0dd88367106390 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:30:56 -0500 Subject: [PATCH 31/35] fix: add links to issues and PRs --- docs/architecture/ADR-003-Non-interactive-defaults.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index f12ef3e2b6..369a937230 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -80,11 +80,11 @@ Arranging the messages in the block to maximize for fees and optimize square spa To meet the above constraints, there are multiple refactors required. - Add metadata to wrapped transactions, connecting that transaction with a message that it pays for. -- Refactor share splitting and merging to use the above metadata when decoding and encoding the square. -- Implement the non-interactive default logic. -- Implement the ability to traverse nmt tree to find subtree roots. -- Refactor `PrepareProposal` to arrange the shares such that each message has the appropriate subtree roots, and so that the metadata connection between transactions and messages is correct. -- Refactor `ProcessProposal` to check for message inclusion using only subtree roots to row roots. +- Refactor share splitting and merging to use the above metadata when decoding and encoding the square. [#462](https://github.com/celestiaorg/celestia-core/issues/462) [#819](https://github.com/celestiaorg/celestia-core/pull/819) [#637](https://github.com/celestiaorg/celestia-app/pull/637) +- Implement the non-interactive default logic. [#680](https://github.com/celestiaorg/celestia-app/pull/680) +- Implement the ability to traverse nmt tree to find subtree roots. [#621](https://github.com/celestiaorg/celestia-app/pull/621) [#545](https://github.com/celestiaorg/celestia-app/pull/549) [#681](https://github.com/celestiaorg/celestia-app/pull/681) +- Refactor `PrepareProposal` to arrange the shares such that each message has the appropriate subtree roots, and so that the metadata connection between transactions and messages is correct. [#692](https://github.com/celestiaorg/celestia-app/pull/692) +- Refactor `ProcessProposal` to check for message inclusion using only subtree roots to row roots. [#747](https://github.com/celestiaorg/celestia-app/pull/747) ### Add metadata to wrapped transactions [#819](https://github.com/celestiaorg/celestia-core/pull/819) From 185e1574c1f746d8bd2067f165170e1275f0d364 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:34:13 -0500 Subject: [PATCH 32/35] fix: use permalinks to the specs --- docs/architecture/ADR-003-Non-interactive-defaults.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 369a937230..17c19fb6f8 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -7,7 +7,7 @@ The exact approach taken by the initial implementation, however, is certainly up ## Intro -please see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md), from which this ADR paraphrases heavily. +please see the [original specs](https://github.com/celestiaorg/celestia-specs/blob/e59efd63a2165866584833e91e1cb8a6ed8c8203/src/rationale/message_block_layout.md), from which this ADR paraphrases heavily. Currently, when checking for message inclusion, validators recreate the share commitment from the messages in the block and compare those with what are signed over in the `MsgPayForData` transactions also in that block. If any commitment is not found in one of the PFD transactions, or if there is a commitment that doesn't have a corresponding message, then they reject that block. @@ -169,7 +169,7 @@ The key to arranging the square into non-interactive defaults is calculating the // largest power of two that fits entirely in the msg or the square size. please // see specs for further details. Assumes that cursor < k, all args are non // negative, and that k is a power of two. -// https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules +// https://github.com/celestiaorg/celestia-specs/blob/e59efd63a2165866584833e91e1cb8a6ed8c8203/src/rationale/message_block_layout.md#non-interactive-default-rules func NextAlignedPowerOfTwo(cursor, msgLen, squareSize int) (int, bool) { // if we're starting at the beginning of the row, then return as there are // no cases where we don't start at 0. @@ -315,8 +315,7 @@ Using some of the non-interactive defaults code above, we can quickly calculate ```go // FitsInSquare uses the non interactive default rules to see if messages of // some lengths will fit in a square of size origSquareSize starting at share -// index cursor. See non-interactive default rules -// https://github.com/celestiaorg/celestia-specs/blob/master/src/rationale/message_block_layout.md#non-interactive-default-rules +// index cursor. func FitsInSquare(cursor, origSquareSize int, msgShareLens ...int) (bool, int) { // if there are 0 messages and the cursor already fits inside the square, // then we already know that everything fits in the square. From 69826cce25e69b231a2952692635acb41f537c06 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Fri, 23 Sep 2022 14:36:01 -0500 Subject: [PATCH 33/35] fix: better wording --- docs/architecture/ADR-003-Non-interactive-defaults.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index 17c19fb6f8..ad4a2197f6 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -384,7 +384,7 @@ func (app *App) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePr #### Malleation -Due to the use of the `parsedTxs` data structure, we can now abstract the malleation process entirely, whereas before it was hard coded into the share proprietary proposal share splitting logic. +Due to the use of the `parsedTxs` data structure, we can now abstract the malleation process entirely, whereas before it was hard coded into the block proposal logic. ```go func (p *parsedTx) malleate(txConf client.TxConfig, squareSize uint64) error { From eb745c89db1feca139b77ba017303b34587b4ca2 Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Mon, 26 Sep 2022 19:13:32 -0500 Subject: [PATCH 34/35] fix: remove comments meant for reviewer --- docs/architecture/ADR-003-Non-interactive-defaults.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/ADR-003-Non-interactive-defaults.md index ad4a2197f6..253f910636 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/ADR-003-Non-interactive-defaults.md @@ -461,7 +461,7 @@ Fortunately, most of the work necessary for non-interactive defaults is encapsul - All messages must be ordered lexicographically by namespace. - The commitments signed over in each `MsgPayForData` must consist only of subtree roots of the data square. - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. -- There must not be a message without a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- There must not be a message without a `MsgPayForData`. We are already checking the first constraint simply be calculating the data root. The only changes we need to make here are to cache the nmt trees generated when comparing the data root, and then use those cached trees to find the subtree roots necessary to create the data commitments. @@ -642,7 +642,7 @@ func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponsePr Lastly, we also need to check that each valid `MsgPayForData` has a corresponding message, and that there are no unexpected messages. - If a `MsgPayForData` is added to the square, then its corresponding message must also be included. -- There must not be a message without a `MsgPayForData` (does this need to be a rule? cc @adlerjohn). +- There must not be a message without a `MsgPayForData`. ```go func (app *App) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { From dd66693f5724321fa85e9a4105a579e5ad55afad Mon Sep 17 00:00:00 2001 From: evan-forbes Date: Mon, 26 Sep 2022 19:16:30 -0500 Subject: [PATCH 35/35] fix: rename to adr006 --- ...eractive-defaults.md => adr-006-non-interactive-defaults.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/architecture/{ADR-003-Non-interactive-defaults.md => adr-006-non-interactive-defaults.md} (99%) diff --git a/docs/architecture/ADR-003-Non-interactive-defaults.md b/docs/architecture/adr-006-non-interactive-defaults.md similarity index 99% rename from docs/architecture/ADR-003-Non-interactive-defaults.md rename to docs/architecture/adr-006-non-interactive-defaults.md index 253f910636..c95a5d161a 100644 --- a/docs/architecture/ADR-003-Non-interactive-defaults.md +++ b/docs/architecture/adr-006-non-interactive-defaults.md @@ -1,4 +1,4 @@ -# ADR 003: Non-interactive Defaults, Wrapped Transactions, and Subtree Root Message Inclusion Checks +# ADR 006: Non-interactive Defaults, Wrapped Transactions, and Subtree Root Message Inclusion Checks > **Note** > Unlike normal tendermint/cosmos ADRs, this ADR isn't for deciding on whether or not we will implement non-interactive defaults. The goal of this document is to help reviewers and future readers understand what non-interactive defaults are, the considerations that went into the initial implementation, and how it differs from the original specs.