Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7aba2e7
small fixes
facundomedica Aug 28, 2024
8f3e2cb
update upgrading md
facundomedica Aug 29, 2024
83fa1f0
do not chekc the sequence in prepareproposal
facundomedica Aug 30, 2024
75e79c0
fix
facundomedica Aug 30, 2024
33665d5
double-check this, not sure
facundomedica Sep 3, 2024
0661845
update
facundomedica Sep 4, 2024
c100377
merge main
facundomedica Sep 4, 2024
af42e6c
use mkdirall instead of just mkdir
facundomedica Sep 4, 2024
32ec055
revert to re-do
facundomedica Sep 4, 2024
a06cc3f
re-add skip of seq in prepareproposal
facundomedica Sep 4, 2024
8a5018e
fix close
facundomedica Sep 4, 2024
5109b45
fix
facundomedica Sep 5, 2024
d86bfd4
remove benchmark
facundomedica Sep 5, 2024
8031960
update upgrading.md
facundomedica Sep 5, 2024
9be58bd
use preblock on simapp v1
facundomedica Sep 5, 2024
7ccca5d
rollback change in test
facundomedica Sep 5, 2024
efee58b
Merge branch 'main' into facu/fixunorderedtx-audit
facundomedica Sep 5, 2024
74c1faa
Merge branch 'main' of https://github.com/cosmos/cosmos-sdk into facu…
facundomedica Sep 5, 2024
d29c921
Merge branch 'facu/fixunorderedtx-audit' of https://github.com/cosmos…
facundomedica Sep 5, 2024
7b3ffef
Merge branch 'main' into facu/fixunorderedtx-audit
facundomedica Sep 6, 2024
804415f
merge
facundomedica Sep 9, 2024
0b9141a
timestamp and height
facundomedica Sep 9, 2024
dcc9705
Revert "timestamp and height"
facundomedica Sep 9, 2024
4b30492
we don't care about timestamp in snapshot
facundomedica Sep 9, 2024
cf9fd70
finally fix this
facundomedica Sep 10, 2024
274c596
fix test
facundomedica Sep 11, 2024
0fcc166
comment
facundomedica Sep 11, 2024
9974f61
remove test prints
facundomedica Sep 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,23 @@ If you are still using the legacy wiring, you must enable unordered transactions
}
```

* Create or update the App's `Precommiter()` method to call the unordered tx
manager's `OnNewBlock()` method.

```go
...
app.SetPrecommiter(app.Precommiter)
...

func (app *SimApp) Precommiter(ctx sdk.Context) {
if err := app.ModuleManager.Precommit(ctx); err != nil {
panic(err)
}

app.UnorderedTxManager.OnNewBlock(ctx.BlockTime())
}
```

* Create or update the App's `Close()` method to close the unordered tx manager.
Note, this is critical as it ensures the manager's state is written to file
such that when the node restarts, it can recover the state to provide replay
Expand Down
83 changes: 46 additions & 37 deletions baseapp/abci_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,35 +292,41 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
invalidTxs []sdk.Tx // invalid txs to be removed out of the loop to avoid dead lock
)
h.mempool.SelectBy(ctx, req.Txs, func(memTx sdk.Tx) bool {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}

// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
unorderedTx, ok := memTx.(sdk.TxWithUnordered)
isUnordered := ok && unorderedTx.GetUnordered()
txSignersSeqs := make(map[string]uint64)
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue

// if the tx is unordered, we don't need to check the sequence, we just add it
if !isUnordered {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}

// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue
}

// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}

// NOTE: Since transaction verification was already executed in CheckTx,
Expand All @@ -337,18 +343,21 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
}

txsLen := len(h.txSelector.SelectedTxs(ctx))
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
// If the tx is unordered, we don't need to update the sender sequence.
if !isUnordered {
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
}
}
}
selectedTxsNums = txsLen
Expand Down
9 changes: 9 additions & 0 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,7 @@ func NewSimApp(
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.setAnteHandler(txConfig)
app.SetPrecommiter(app.Precommiter)

// In v0.46, the SDK introduces _postHandlers_. PostHandlers are like
// antehandlers, but are run _after_ the `runMsgs` execution. They are also
Expand Down Expand Up @@ -699,6 +700,14 @@ func (app *SimApp) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) {
return app.ModuleManager.EndBlock(ctx)
}

func (app *SimApp) Precommiter(ctx sdk.Context) {
if err := app.ModuleManager.Precommit(ctx); err != nil {
panic(err)
}

app.UnorderedTxManager.OnNewBlock(ctx.BlockTime())
}

func (a *SimApp) Configurator() module.Configurator { // nolint:staticcheck // SA1019: Configurator is deprecated but still used in runtime v1.
return a.configurator
}
Expand Down
31 changes: 31 additions & 0 deletions simapp/app_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
_ "embed"
"fmt"
"io"
"path/filepath"

clienthelpers "cosmossdk.io/client/v2/helpers"
"cosmossdk.io/core/address"
Expand Down Expand Up @@ -35,6 +36,7 @@ import (

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
Expand All @@ -43,13 +45,15 @@ import (
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/spf13/cast"
)

// DefaultNodeHome default home directories for the application daemon
Expand Down Expand Up @@ -268,6 +272,16 @@ func NewSimApp(
// return app.App.InitChainer(ctx, req)
// })

// create, start, and load the unordered tx manager
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be deleted, runtime has it.

utxDataDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data")
app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir)
app.UnorderedTxManager.Start()
app.SetPrecommiter(app.Precommiter)

if err := app.UnorderedTxManager.OnInit(); err != nil {
panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err))
}

// register custom snapshot extensions (if any)
if manager := app.SnapshotManager(); manager != nil {
if err := manager.RegisterExtensions(
Expand Down Expand Up @@ -312,6 +326,23 @@ func (app *SimApp) setCustomAnteHandler() {
app.SetAnteHandler(anteHandler)
}

func (app *SimApp) Precommiter(ctx sdk.Context) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have runtime have this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: thinking about it, I don't think we should use this.

if err := app.ModuleManager.Precommit(ctx); err != nil {
panic(err)
}

app.UnorderedTxManager.OnNewBlock(ctx.BlockTime())
}

// Close implements the Application interface and closes all necessary application
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, should be deleted, runtime abstracts it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, didn't realize it was there already

// resources.
func (app *SimApp) Close() error {
if err := app.BaseApp.Close(); err != nil {
return err
}
return app.UnorderedTxManager.Close()
}

// LegacyAmino returns SimApp's amino codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
Expand Down
19 changes: 19 additions & 0 deletions types/mempool/priority_nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error
sender := sig.Signer.String()
priority := mp.cfg.TxPriority.GetTxPriority(ctx, tx)
nonce := sig.Sequence

// if it's an unordered tx, we use the gas instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
gasLimit, err := unordered.GetGasLimit()
nonce = gasLimit
if err != nil {
return err
}
}

key := txMeta[C]{nonce: nonce, priority: priority, sender: sender}

senderIndex, ok := mp.senderIndices[sender]
Expand Down Expand Up @@ -459,6 +469,15 @@ func (mp *PriorityNonceMempool[C]) Remove(tx sdk.Tx) error {
sender := sig.Signer.String()
nonce := sig.Sequence

// if it's an unordered tx, we use the gas instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
gasLimit, err := unordered.GetGasLimit()
nonce = gasLimit
if err != nil {
return err
}
}

scoreKey := txMeta[C]{nonce: nonce, sender: sender}
score, ok := mp.scores[scoreKey]
if !ok {
Expand Down
18 changes: 18 additions & 0 deletions types/mempool/sender_nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error {
snm.senders[sender] = senderTxs
}

// if it's an unordered tx, we use the gas instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
gasLimit, err := unordered.GetGasLimit()
nonce = gasLimit
if err != nil {
return err
}
}

senderTxs.Set(nonce, tx)

key := txKey{nonce: nonce, address: sender}
Expand Down Expand Up @@ -227,6 +236,15 @@ func (snm *SenderNonceMempool) Remove(tx sdk.Tx) error {
sender := sdk.AccAddress(sig.PubKey.Address()).String()
nonce := sig.Sequence

// if it's an unordered tx, we use the gas instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
gasLimit, err := unordered.GetGasLimit()
nonce = gasLimit
if err != nil {
return err
}
}

senderTxs, found := snm.senders[sender]
if !found {
return ErrTxNotFound
Expand Down
8 changes: 5 additions & 3 deletions x/auth/ante/unorderedtx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ type Manager struct {
func NewManager(dataDir string) *Manager {
path := filepath.Join(dataDir, dirName)
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
_ = os.Mkdir(path, os.ModePerm)
if err = os.MkdirAll(path, os.ModePerm); err != nil {
panic(fmt.Errorf("failed to create unordered txs directory: %w", err))
}
}

m := &Manager{
Expand Down Expand Up @@ -185,8 +187,8 @@ func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) erro
return snapshotWriter(buf.Bytes())
}

// flushToFile writes all unexpired unordered transactions along with their TTL
// to file, overwriting the existing file if it exists.
// flushToFile writes all unordered transactions (including expired if not pruned yet)
// along with their TTL to file, overwriting the existing file if it exists.
func (m *Manager) flushToFile() error {
f, err := os.Create(filepath.Join(m.dataDir, dirName, fileName))
if err != nil {
Expand Down