fix: use contents of the tx as identifier in cache (#20533)
Co-authored-by: Alexander Peters <alpe@users.noreply.github.com>
This commit is contained in:
parent
e3ea68aa1a
commit
2cf378174d
@ -361,6 +361,7 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
|
||||
tx.SetFeeGranter(f.feeGranter)
|
||||
tx.SetFeePayer(f.feePayer)
|
||||
tx.SetTimeoutHeight(f.TimeoutHeight())
|
||||
tx.SetUnordered(f.Unordered())
|
||||
|
||||
if etx, ok := tx.(client.ExtendedTxBuilder); ok {
|
||||
etx.SetExtensionOptions(f.extOptions...)
|
||||
|
||||
@ -9,11 +9,8 @@ require (
|
||||
cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91
|
||||
cosmossdk.io/x/gov v0.0.0-20231113122742-912390d5fc4a
|
||||
cosmossdk.io/x/tx v0.13.3
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5
|
||||
github.com/cosmos/cosmos-sdk v0.51.0
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
google.golang.org/grpc v1.64.1
|
||||
@ -43,6 +40,8 @@ require (
|
||||
github.com/bgentry/speakeasy v0.2.0 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chzyer/readline v1.5.1 // indirect
|
||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/pebble v1.1.0 // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
@ -113,6 +112,7 @@ require (
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/linxGnu/grocksdb v1.8.14 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
|
||||
@ -235,7 +235,6 @@ func ProvideModuleC(key StoreKey, b KeeperB) KeeperC {
|
||||
|
||||
type keeperC struct {
|
||||
key StoreKey
|
||||
b KeeperB
|
||||
}
|
||||
|
||||
type KeeperC interface {
|
||||
|
||||
@ -261,15 +261,35 @@ func (d *DedupTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
|
||||
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL)
|
||||
}
|
||||
|
||||
// check for duplicates
|
||||
if d.m.Contains(tx.Hash()) {
|
||||
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "tx is duplicated")
|
||||
}
|
||||
// in order to create a deterministic hash based on the tx, we need to hash the contents of the tx with signature
|
||||
// Get a Buffer from the pool
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
// Make sure to reset the buffer
|
||||
buf.Reset()
|
||||
|
||||
if !ctx.IsCheckTx() {
|
||||
// a new tx included in the block, add the hash to the unordered tx manager
|
||||
d.m.Add(tx.Hash(), tx.TimeoutHeight())
|
||||
}
|
||||
// Use the buffer
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
// loop through the messages and write them to the buffer
|
||||
// encoding the msg to bytes makes it deterministic within the state machine.
|
||||
// Malleability is not a concern here because the state machine will encode the transaction deterministically.
|
||||
bz, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "failed to marshal message")
|
||||
}
|
||||
|
||||
buf.Write(bz)
|
||||
}
|
||||
|
||||
// check for duplicates
|
||||
// check for duplicates
|
||||
if d.txManager.Contains(txHash) {
|
||||
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated")
|
||||
}
|
||||
|
||||
if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize {
|
||||
// a new tx included in the block, add the hash to the unordered tx manager
|
||||
d.txManager.Add(txHash, ttl)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@ -282,10 +302,7 @@ encoding is not malleable. If a given transaction, which is otherwise valid, can
|
||||
be encoded to produce different hashes, which reflect the same valid transaction,
|
||||
then a duplicate unordered transaction can be submitted and included in a block.
|
||||
|
||||
In order to prevent this, transactions should be encoded in a deterministic manner.
|
||||
[ADR-027](./adr-027-deterministic-protobuf-serialization.md) provides such a mechanism.
|
||||
However, it is important to note that the way a transaction is signed should ensure
|
||||
ADR-027 is followed. E.g. we want to avoid Amino signing.
|
||||
In order to prevent this, the decoded transaction contents is taken. Starting with the content of the transaction we marshal the transaction in order to prevent a client reordering the transaction. Next we include the gas and timeout height as part of the identifier. All these fields are signed over in the transaction payload. If one of them changes the signature will not match the transaction.
|
||||
|
||||
### State Management
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
||||
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
|
||||
ante.NewValidateBasicDecorator(options.Environment),
|
||||
ante.NewTxTimeoutHeightDecorator(options.Environment),
|
||||
ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, options.TxManager, options.Environment),
|
||||
ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, options.TxManager, options.Environment, ante.DefaultSha256Cost),
|
||||
ante.NewValidateMemoDecorator(options.AccountKeeper),
|
||||
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
|
||||
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
|
||||
|
||||
@ -9,8 +9,8 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/log"
|
||||
"cosmossdk.io/depinject"
|
||||
"cosmossdk.io/log"
|
||||
_ "cosmossdk.io/x/accounts" // import as blank for app wiring
|
||||
_ "cosmossdk.io/x/auth" // import as blank for app wiring
|
||||
authkeeper "cosmossdk.io/x/auth/keeper"
|
||||
|
||||
@ -44,7 +44,7 @@ type TestnetInitializer interface {
|
||||
type SystemUnderTest struct {
|
||||
execBinary string
|
||||
blockListener *EventListener
|
||||
currentHeight int64
|
||||
currentHeight atomic.Int64
|
||||
outputDir string
|
||||
testnetInitializer TestnetInitializer
|
||||
|
||||
@ -164,7 +164,7 @@ func (s *SystemUnderTest) StartChain(t *testing.T, xargs ...string) {
|
||||
s.blockListener.Subscribe("tm.event='NewBlock'", func(e ctypes.ResultEvent) (more bool) {
|
||||
newBlock, ok := e.Data.(tmtypes.EventDataNewBlock)
|
||||
require.True(t, ok, "unexpected type %T", e.Data)
|
||||
atomic.StoreInt64(&s.currentHeight, newBlock.Block.Height)
|
||||
s.currentHeight.Store(newBlock.Block.Height)
|
||||
return true
|
||||
}),
|
||||
)
|
||||
@ -362,12 +362,12 @@ func (s *SystemUnderTest) PrintBuffer() {
|
||||
// AwaitBlockHeight blocks until te target height is reached. An optional timeout parameter can be passed to abort early
|
||||
func (s *SystemUnderTest) AwaitBlockHeight(t *testing.T, targetHeight int64, timeout ...time.Duration) {
|
||||
t.Helper()
|
||||
require.Greater(t, targetHeight, s.currentHeight)
|
||||
require.Greater(t, targetHeight, s.currentHeight.Load())
|
||||
var maxWaitTime time.Duration
|
||||
if len(timeout) != 0 {
|
||||
maxWaitTime = timeout[0]
|
||||
} else {
|
||||
maxWaitTime = time.Duration(targetHeight-s.currentHeight+3) * s.blockTime
|
||||
maxWaitTime = time.Duration(targetHeight-s.currentHeight.Load()+3) * s.blockTime
|
||||
}
|
||||
abort := time.NewTimer(maxWaitTime).C
|
||||
for {
|
||||
@ -393,10 +393,10 @@ func (s *SystemUnderTest) AwaitNextBlock(t *testing.T, timeout ...time.Duration)
|
||||
}
|
||||
done := make(chan int64)
|
||||
go func() {
|
||||
for start, current := atomic.LoadInt64(&s.currentHeight), atomic.LoadInt64(&s.currentHeight); current == start; current = atomic.LoadInt64(&s.currentHeight) {
|
||||
for start, current := s.currentHeight.Load(), s.currentHeight.Load(); current == start; current = s.currentHeight.Load() {
|
||||
time.Sleep(s.blockTime)
|
||||
}
|
||||
done <- atomic.LoadInt64(&s.currentHeight)
|
||||
done <- s.currentHeight.Load()
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
@ -434,7 +434,7 @@ func (s *SystemUnderTest) ResetChain(t *testing.T) {
|
||||
|
||||
// reset all validator nodes
|
||||
s.ForEachNodeExecAndWait(t, []string{"comet", "unsafe-reset-all"})
|
||||
s.currentHeight = 0
|
||||
s.currentHeight.Store(0)
|
||||
s.dirty = false
|
||||
}
|
||||
|
||||
@ -465,7 +465,7 @@ func (s *SystemUnderTest) ModifyGenesisJSON(t *testing.T, mutators ...GenesisMut
|
||||
// modify json without enforcing a reset
|
||||
func (s *SystemUnderTest) modifyGenesisJSON(t *testing.T, mutators ...GenesisMutator) {
|
||||
t.Helper()
|
||||
require.Empty(t, s.currentHeight, "forced chain reset required")
|
||||
require.Empty(t, s.currentHeight.Load(), "forced chain reset required")
|
||||
current, err := os.ReadFile(filepath.Join(WorkDir, s.nodePath(0), "config", "genesis.json"))
|
||||
require.NoError(t, err)
|
||||
for _, m := range mutators {
|
||||
@ -727,6 +727,10 @@ func (s *SystemUnderTest) anyNodeRunning() bool {
|
||||
return len(s.pids) != 0
|
||||
}
|
||||
|
||||
func (s *SystemUnderTest) CurrentHeight() int64 {
|
||||
return s.currentHeight.Load()
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
ID string
|
||||
IP string
|
||||
|
||||
52
tests/systemtests/unordered_tx_test.go
Normal file
52
tests/systemtests/unordered_tx_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
//go:build system_test
|
||||
|
||||
package systemtests
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUnorderedTXDuplicate(t *testing.T) {
|
||||
// scenario: test unordered tx duplicate
|
||||
// given a running chain with a tx in the unordered tx pool
|
||||
// when a new tx with the same hash is broadcasted
|
||||
// then the new tx should be rejected
|
||||
|
||||
sut.ResetChain(t)
|
||||
cli := NewCLIWrapper(t, sut, verbose)
|
||||
// add genesis account with some tokens
|
||||
account1Addr := cli.AddKey("account1")
|
||||
account2Addr := cli.AddKey("account2")
|
||||
sut.ModifyGenesisCLI(t,
|
||||
[]string{"genesis", "add-genesis-account", account1Addr, "10000000stake"},
|
||||
)
|
||||
|
||||
sut.StartChain(t)
|
||||
|
||||
height := sut.CurrentHeight()
|
||||
timeoutHeight := height + 15
|
||||
timeoutHeightStr := strconv.Itoa(int(timeoutHeight))
|
||||
// send tokens
|
||||
rsp1 := cli.Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", "--timeout-height="+timeoutHeightStr, "--unordered", "--sequence=1", "--note=1")
|
||||
RequireTxSuccess(t, rsp1)
|
||||
|
||||
assertDuplicateErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
|
||||
require.Len(t, gotOutputs, 1)
|
||||
assert.Contains(t, gotOutputs[0], "is duplicated: invalid request")
|
||||
return false // always abort
|
||||
}
|
||||
rsp2 := cli.WithRunErrorMatcher(assertDuplicateErr).Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", "--timeout-height="+timeoutHeightStr, "--unordered", "--sequence=1")
|
||||
RequireTxFailure(t, rsp2)
|
||||
|
||||
// assert TX executed before timeout
|
||||
for cli.QueryBalance(account2Addr, "stake") != 5000 {
|
||||
t.Log("query balance")
|
||||
if current := sut.AwaitNextBlock(t); current > timeoutHeight {
|
||||
t.Fatal("TX was not executed before timeout")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,12 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/protobuf/proto" // nolint: staticcheck // for proto.Message
|
||||
|
||||
"cosmossdk.io/core/appmodule/v2"
|
||||
"cosmossdk.io/core/transaction"
|
||||
@ -12,6 +17,15 @@ import (
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// bufPool is a pool of bytes.Buffer objects to reduce memory allocations.
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
const DefaultSha256Cost = 25
|
||||
|
||||
var _ sdk.AnteDecorator = (*UnorderedTxDecorator)(nil)
|
||||
|
||||
// UnorderedTxDecorator defines an AnteHandler decorator that is responsible for
|
||||
@ -31,13 +45,15 @@ type UnorderedTxDecorator struct {
|
||||
maxUnOrderedTTL uint64
|
||||
txManager *unorderedtx.Manager
|
||||
env appmodule.Environment
|
||||
sha256Cost uint64
|
||||
}
|
||||
|
||||
func NewUnorderedTxDecorator(maxTTL uint64, m *unorderedtx.Manager, env appmodule.Environment) *UnorderedTxDecorator {
|
||||
func NewUnorderedTxDecorator(maxTTL uint64, m *unorderedtx.Manager, env appmodule.Environment, gasCost uint64) *UnorderedTxDecorator {
|
||||
return &UnorderedTxDecorator{
|
||||
maxUnOrderedTTL: maxTTL,
|
||||
txManager: m,
|
||||
env: env,
|
||||
sha256Cost: gasCost,
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,13 +78,27 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne
|
||||
return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL)
|
||||
}
|
||||
|
||||
txHash := sha256.Sum256(ctx.TxBytes())
|
||||
// consume gas in all exec modes to avoid gas estimation discrepancies
|
||||
if err := d.env.GasService.GasMeter(ctx).Consume(d.sha256Cost, "consume gas for calculating tx hash"); err != nil {
|
||||
return ctx, errorsmod.Wrap(sdkerrors.ErrOutOfGas, "out of gas")
|
||||
}
|
||||
|
||||
// Avoid checking for duplicates and creating the identifier in simulation mode
|
||||
// This is done to avoid sha256 computation in simulation mode
|
||||
if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeSimulate {
|
||||
return next(ctx, tx, false)
|
||||
}
|
||||
|
||||
// calculate the tx hash
|
||||
txHash, err := TxIdentifier(ttl, tx)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// check for duplicates
|
||||
if d.txManager.Contains(txHash) {
|
||||
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated")
|
||||
}
|
||||
|
||||
if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize {
|
||||
// a new tx included in the block, add the hash to the unordered tx manager
|
||||
d.txManager.Add(txHash, ttl)
|
||||
@ -76,3 +106,46 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne
|
||||
|
||||
return next(ctx, tx, false)
|
||||
}
|
||||
|
||||
// TxIdentifier returns a unique identifier for a transaction that is intended to be unordered.
|
||||
func TxIdentifier(timeout uint64, tx sdk.Tx) ([32]byte, error) {
|
||||
feetx := tx.(sdk.FeeTx)
|
||||
if feetx.GetFee().IsZero() {
|
||||
return [32]byte{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have a fee")
|
||||
}
|
||||
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
// Make sure to reset the buffer
|
||||
buf.Reset()
|
||||
defer bufPool.Put(buf)
|
||||
|
||||
// Use the buffer
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
// loop through the messages and write them to the buffer
|
||||
// encoding the msg to bytes makes it deterministic within the state machine.
|
||||
// Malleability is not a concern here because the state machine will encode the transaction deterministically.
|
||||
bz, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return [32]byte{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "failed to marshal message")
|
||||
}
|
||||
|
||||
if _, err := buf.Write(bz); err != nil {
|
||||
return [32]byte{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "failed to write message to buffer")
|
||||
}
|
||||
}
|
||||
|
||||
// write the timeout height to the buffer
|
||||
if err := binary.Write(buf, binary.LittleEndian, timeout); err != nil {
|
||||
return [32]byte{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "failed to write timeout_height to buffer")
|
||||
}
|
||||
|
||||
// write gas to the buffer
|
||||
if err := binary.Write(buf, binary.LittleEndian, feetx.GetGas()); err != nil {
|
||||
return [32]byte{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "failed to write unordered to buffer")
|
||||
}
|
||||
|
||||
txHash := sha256.Sum256(buf.Bytes())
|
||||
|
||||
// Return the Buffer to the pool
|
||||
return txHash, nil
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/auth/ante"
|
||||
"cosmossdk.io/x/auth/ante/unorderedtx"
|
||||
|
||||
@ -15,6 +15,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
)
|
||||
|
||||
const gasConsumed = uint64(25)
|
||||
|
||||
func TestUnorderedTxDecorator_OrderedTx(t *testing.T) {
|
||||
txm := unorderedtx.NewManager(t.TempDir())
|
||||
defer func() {
|
||||
@ -25,7 +27,7 @@ func TestUnorderedTxDecorator_OrderedTx(t *testing.T) {
|
||||
|
||||
suite := SetupTestSuite(t, false)
|
||||
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment()))
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost))
|
||||
|
||||
tx, txBz := genUnorderedTx(t, false, 0)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100)
|
||||
@ -44,7 +46,7 @@ func TestUnorderedTxDecorator_UnorderedTx_NoTTL(t *testing.T) {
|
||||
|
||||
suite := SetupTestSuite(t, false)
|
||||
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment()))
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost))
|
||||
|
||||
tx, txBz := genUnorderedTx(t, true, 0)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100)
|
||||
@ -63,7 +65,7 @@ func TestUnorderedTxDecorator_UnorderedTx_InvalidTTL(t *testing.T) {
|
||||
|
||||
suite := SetupTestSuite(t, false)
|
||||
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment()))
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost))
|
||||
|
||||
tx, txBz := genUnorderedTx(t, true, 100+unorderedtx.DefaultMaxUnOrderedTTL+1)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100)
|
||||
@ -82,13 +84,14 @@ func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) {
|
||||
|
||||
suite := SetupTestSuite(t, false)
|
||||
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment()))
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost))
|
||||
|
||||
tx, txBz := genUnorderedTx(t, true, 150)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithGasMeter(storetypes.NewGasMeter(gasConsumed))
|
||||
|
||||
txHash := sha256.Sum256(txBz)
|
||||
txm.Add(txHash, 150)
|
||||
bz := [32]byte{}
|
||||
copy(bz[:], txBz[:32])
|
||||
txm.Add(bz, 150)
|
||||
|
||||
_, err := chain(ctx, tx, false)
|
||||
require.Error(t, err)
|
||||
@ -104,10 +107,10 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) {
|
||||
|
||||
suite := SetupTestSuite(t, false)
|
||||
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment()))
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost))
|
||||
|
||||
tx, txBz := genUnorderedTx(t, true, 150)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeCheck)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeCheck).WithGasMeter(storetypes.NewGasMeter(gasConsumed))
|
||||
|
||||
_, err := chain(ctx, tx, false)
|
||||
require.NoError(t, err)
|
||||
@ -123,16 +126,18 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) {
|
||||
|
||||
suite := SetupTestSuite(t, false)
|
||||
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment()))
|
||||
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost))
|
||||
|
||||
tx, txBz := genUnorderedTx(t, true, 150)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeFinalize)
|
||||
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeFinalize).WithGasMeter(storetypes.NewGasMeter(gasConsumed))
|
||||
|
||||
_, err := chain(ctx, tx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
txHash := sha256.Sum256(txBz)
|
||||
require.True(t, txm.Contains(txHash))
|
||||
bz := [32]byte{}
|
||||
copy(bz[:], txBz[:32])
|
||||
|
||||
require.True(t, txm.Contains(bz))
|
||||
}
|
||||
|
||||
func genUnorderedTx(t *testing.T, unordered bool, ttl uint64) (sdk.Tx, []byte) {
|
||||
@ -159,8 +164,9 @@ func genUnorderedTx(t *testing.T, unordered bool, ttl uint64) (sdk.Tx, []byte) {
|
||||
tx, err := s.CreateTestTx(s.ctx, privKeys, accNums, accSeqs, s.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
|
||||
require.NoError(t, err)
|
||||
|
||||
txBz, err := s.encCfg.TxConfig.TxEncoder()(tx)
|
||||
txBz, err := ante.TxIdentifier(ttl, tx)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
return tx, txBz
|
||||
return tx, txBz[:]
|
||||
}
|
||||
|
||||
@ -3,12 +3,10 @@ module cosmossdk.io/x/authz
|
||||
go 1.22.2
|
||||
|
||||
require (
|
||||
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
|
||||
cosmossdk.io/api v0.7.5
|
||||
cosmossdk.io/core v0.12.1-0.20231114100755-569e3ff6a0d7
|
||||
cosmossdk.io/depinject v1.0.0-alpha.4
|
||||
cosmossdk.io/errors v1.0.1
|
||||
cosmossdk.io/log v1.3.1
|
||||
cosmossdk.io/math v1.3.0
|
||||
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc
|
||||
cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91
|
||||
@ -168,6 +166,8 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
|
||||
cosmossdk.io/log v1.3.1 // indirect
|
||||
cosmossdk.io/schema v0.1.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
)
|
||||
@ -182,6 +182,8 @@ replace (
|
||||
cosmossdk.io/core/testing => ../../core/testing
|
||||
cosmossdk.io/depinject => ../../depinject
|
||||
cosmossdk.io/log => ../../log
|
||||
cosmossdk.io/logger => ../../logger
|
||||
cosmossdk.io/store => ../../store
|
||||
cosmossdk.io/x/accounts => ../accounts
|
||||
cosmossdk.io/x/auth => ../auth
|
||||
cosmossdk.io/x/bank => ../bank
|
||||
|
||||
@ -10,8 +10,6 @@ cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE=
|
||||
cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k=
|
||||
cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA=
|
||||
cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
|
||||
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc h1:R9O9d75e0qZYUsVV0zzi+D7cNLnX2JrUOQNoIPaF0Bg=
|
||||
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc/go.mod h1:amTTatOUV3u1PsKmNb87z6/galCxrRbz9kRdJkL0DyU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/core/log"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/authz/keeper"
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
gogoproto "github.com/cosmos/gogoproto/proto"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
corecontext "cosmossdk.io/core/context"
|
||||
@ -65,7 +65,7 @@ func (k Keeper) update(ctx context.Context, grantee, granter sdk.AccAddress, upd
|
||||
return authz.ErrNoAuthorizationFound
|
||||
}
|
||||
|
||||
msg, ok := updated.(proto.Message)
|
||||
msg, ok := updated.(gogoproto.Message)
|
||||
if !ok {
|
||||
return sdkerrors.ErrPackAny.Wrapf("cannot proto marshal %T", updated)
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/core/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/authz"
|
||||
authzkeeper "cosmossdk.io/x/authz/keeper"
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
|
||||
govtypes "cosmossdk.io/api/cosmos/gov/v1beta1"
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/core/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
"cosmossdk.io/x/authz"
|
||||
v2 "cosmossdk.io/x/authz/migrations/v2"
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/core/log"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
authtypes "cosmossdk.io/x/auth/types"
|
||||
"cosmossdk.io/x/authz"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user