Skip to content

Commit

Permalink
feat(adapters): Add SignerExtractionAdapter [ENG-1916] (#114) (#129)
Browse files Browse the repository at this point in the history
* add a signer-extraction-adapter

* linting

* feat(adapters/mev-lane):  Use the SignerExtractionAdapter in the Mev-Lane [ENG-1917] (#115)

* use SignerExtractionAdapter in the Factory

* feat(e2e): block sdk integration updates (#122)

* cherry-pick from injective

* remove transactions from app-side mempool on failed re-checktx

Co-authored-by: Nikhil Vasan <[email protected]>
  • Loading branch information
mergify[bot] and nivasan1 authored Sep 27, 2023
1 parent 35ef413 commit 2bb89fd
Show file tree
Hide file tree
Showing 26 changed files with 885 additions and 478 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ TEST_INTEGRATION_TAGS = integration

test-integration: $(TEST_INTEGRATION_DEPS)
@ echo "Running integration tests..."
@go test ./tests/integration/pob_integration_test.go -timeout 30m -race -v -tags='$(TEST_INTEGRATION_TAGS)'
@go test ./tests/integration/block_sdk_integration_test.go -timeout 30m -p 1 -race -v -tags='$(TEST_INTEGRATION_TAGS)'

test: use-main
@go test -v -race $(shell go list ./... | grep -v tests/)
Expand Down
47 changes: 26 additions & 21 deletions abci/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/block-sdk/abci"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
defaultlane "github.com/skip-mev/block-sdk/lanes/base"
Expand Down Expand Up @@ -717,52 +718,56 @@ func (s *ProposalsTestSuite) setUpAnteHandler(expectedExecution map[sdk.Tx]bool)

func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *defaultlane.DefaultLane {
cfg := base.LaneConfig{
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
}

return defaultlane.NewDefaultLane(cfg)
}

func (s *ProposalsTestSuite) setUpTOBLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *mev.MEVLane {
cfg := base.LaneConfig{
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: maxBlockSpace,
}

return mev.NewMEVLane(cfg, mev.NewDefaultAuctionFactory(cfg.TxDecoder))
return mev.NewMEVLane(cfg, mev.NewDefaultAuctionFactory(cfg.TxDecoder, signer_extraction.NewDefaultAdapter()))
}

func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *free.FreeLane {
cfg := base.LaneConfig{
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: maxBlockSpace,
}

return free.NewFreeLane(cfg, base.DefaultTxPriority(), free.DefaultMatchHandler())
}

func (s *ProposalsTestSuite) setUpPanicLane(maxBlockSpace math.LegacyDec) *base.BaseLane {
cfg := base.LaneConfig{
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTMLogger(os.Stdout),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: maxBlockSpace,
}

lane := base.NewBaseLane(
cfg,
"panic",
base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, 0),
base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, signer_extraction.NewDefaultAdapter(), 0),
base.DefaultMatchHandler(),
)

Expand Down
51 changes: 51 additions & 0 deletions adapters/signer_extraction_adapter/signer_extraction_adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package signerextraction

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)

type SignerData struct {
Signer sdk.AccAddress
Sequence uint64
}

// SignerExtractionAdapter is an interface used to determine how the signers of a transaction should be extracted
// from the transaction.
type Adapter interface {
GetSigners(sdk.Tx) ([]SignerData, error)
}

var _ Adapter = DefaultAdapter{}

// DefaultSignerExtractionAdapter is the default implementation of SignerExtractionAdapter. It extracts the signers
// from a cosmos-sdk tx via GetSignaturesV2.
type DefaultAdapter struct{}

func NewDefaultAdapter() DefaultAdapter {
return DefaultAdapter{}
}

func (DefaultAdapter) GetSigners(tx sdk.Tx) ([]SignerData, error) {
sigTx, ok := tx.(signing.SigVerifiableTx)
if !ok {
return nil, fmt.Errorf("tx of type %T does not implement SigVerifiableTx", tx)
}

sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return nil, err
}

signers := make([]SignerData, len(sigs))
for i, sig := range sigs {
signers[i] = SignerData{
Signer: sig.PubKey.Address().Bytes(),
Sequence: sig.Sequence,
}
}

return signers, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package signerextraction_test

import (
"math/rand"
"testing"

"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
testutils "github.com/skip-mev/block-sdk/testutils"
"github.com/stretchr/testify/suite"
)

type SignerExtractionAdapterTestSuite struct {
suite.Suite
txConfig client.TxConfig
accts []testutils.Account
adapter signer_extraction.DefaultAdapter
}

func TestSignerExtractionAdapterTestSuite(t *testing.T) {
suite.Run(t, new(SignerExtractionAdapterTestSuite))
}

func (s *SignerExtractionAdapterTestSuite) SetupTest() {
encodingConfig := testutils.CreateTestEncodingConfig()
s.txConfig = encodingConfig.TxConfig

accts := testutils.RandomAccounts(rand.New(rand.NewSource(1)), 2)

s.accts = accts
}

func (s *SignerExtractionAdapterTestSuite) TestGetSigners() {
acct := s.accts[0]
tx, err := testutils.CreateTx(s.txConfig, acct, 1, 1, []sdk.Msg{
&banktypes.MsgSend{
FromAddress: acct.Address.String(),
ToAddress: acct.Address.String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 1)),
},
}, sdk.NewCoins(sdk.NewCoin("test", math.NewInt(1)))...)
s.Require().NoError(err)

signers, err := s.adapter.GetSigners(tx)
s.Require().NoError(err)

s.Require().Len(signers, 1)
s.Require().Equal(acct.Address.String(), signers[0].Signer.String())
s.Require().Equal(uint64(1), signers[0].Sequence)
}
22 changes: 17 additions & 5 deletions block/base/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"cosmossdk.io/math"
"github.com/cometbft/cometbft/libs/log"
sdk "github.com/cosmos/cosmos-sdk/types"

signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
)

Expand All @@ -16,6 +18,10 @@ type LaneConfig struct {
TxDecoder sdk.TxDecoder
AnteHandler sdk.AnteHandler

// SignerExtractor defines the interface used for extracting the expected signers of a transaction
// from the transaction.
SignerExtractor signer_extraction.Adapter

// MaxBlockSpace defines the relative percentage of block space that can be
// used by this lane. NOTE: If this is set to zero, then there is no limit
// on the number of transactions that can be included in the block for this
Expand Down Expand Up @@ -46,14 +52,16 @@ func NewLaneConfig(
txEncoder sdk.TxEncoder,
txDecoder sdk.TxDecoder,
anteHandler sdk.AnteHandler,
signerExtractor signer_extraction.Adapter,
maxBlockSpace math.LegacyDec,
) LaneConfig {
return LaneConfig{
Logger: logger,
TxEncoder: txEncoder,
TxDecoder: txDecoder,
AnteHandler: anteHandler,
MaxBlockSpace: maxBlockSpace,
Logger: logger,
TxEncoder: txEncoder,
TxDecoder: txDecoder,
AnteHandler: anteHandler,
MaxBlockSpace: maxBlockSpace,
SignerExtractor: signerExtractor,
}
}

Expand All @@ -71,6 +79,10 @@ func (c *LaneConfig) ValidateBasic() error {
return fmt.Errorf("tx decoder cannot be nil")
}

if c.SignerExtractor == nil {
return fmt.Errorf("signer extractor cannot be nil")
}

if c.MaxBlockSpace.IsNil() || c.MaxBlockSpace.IsNegative() || c.MaxBlockSpace.GT(math.LegacyOneDec()) {
return fmt.Errorf("max block space must be set to a value between 0 and 1")
}
Expand Down
5 changes: 4 additions & 1 deletion block/base/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"

signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block/utils"
)

Expand Down Expand Up @@ -80,13 +82,14 @@ func DefaultTxPriority() TxPriority[string] {
}

// NewMempool returns a new Mempool.
func NewMempool[C comparable](txPriority TxPriority[C], txEncoder sdk.TxEncoder, maxTx int) *Mempool[C] {
func NewMempool[C comparable](txPriority TxPriority[C], txEncoder sdk.TxEncoder, extractor signer_extraction.Adapter, maxTx int) *Mempool[C] {
return &Mempool[C]{
index: NewPriorityMempool(
PriorityNonceMempoolConfig[C]{
TxPriority: txPriority,
MaxTx: maxTx,
},
extractor,
),
txPriority: txPriority,
txEncoder: txEncoder,
Expand Down
48 changes: 25 additions & 23 deletions block/base/priority_nonce.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
)

var (
Expand Down Expand Up @@ -62,11 +62,12 @@ type (
// priority to other sender txs and must be partially ordered by both sender-nonce
// and priority.
PriorityNonceMempool[C comparable] struct {
priorityIndex *skiplist.SkipList
priorityCounts map[C]int
senderIndices map[string]*skiplist.SkipList
scores map[txMeta[C]]txMeta[C]
cfg PriorityNonceMempoolConfig[C]
priorityIndex *skiplist.SkipList
priorityCounts map[C]int
senderIndices map[string]*skiplist.SkipList
scores map[txMeta[C]]txMeta[C]
cfg PriorityNonceMempoolConfig[C]
signerExtractor signer_extraction.Adapter
}

// PriorityNonceIterator defines an iterator that is used for mempool iteration
Expand Down Expand Up @@ -167,21 +168,22 @@ func skiplistComparable[C comparable](txPriority TxPriority[C]) skiplist.Compara

// NewPriorityMempool returns the SDK's default mempool implementation which
// returns txs in a partial order by 2 dimensions; priority, and sender-nonce.
func NewPriorityMempool[C comparable](cfg PriorityNonceMempoolConfig[C]) *PriorityNonceMempool[C] {
func NewPriorityMempool[C comparable](cfg PriorityNonceMempoolConfig[C], extractor signer_extraction.Adapter) *PriorityNonceMempool[C] {
mp := &PriorityNonceMempool[C]{
priorityIndex: skiplist.New(skiplistComparable(cfg.TxPriority)),
priorityCounts: make(map[C]int),
senderIndices: make(map[string]*skiplist.SkipList),
scores: make(map[txMeta[C]]txMeta[C]),
cfg: cfg,
priorityIndex: skiplist.New(skiplistComparable(cfg.TxPriority)),
priorityCounts: make(map[C]int),
senderIndices: make(map[string]*skiplist.SkipList),
scores: make(map[txMeta[C]]txMeta[C]),
cfg: cfg,
signerExtractor: extractor,
}

return mp
}

// DefaultPriorityMempool returns a priorityNonceMempool with no options.
func DefaultPriorityMempool() *PriorityNonceMempool[int64] {
return NewPriorityMempool(DefaultPriorityNonceMempoolConfig())
func DefaultPriorityMempool(extractor signer_extraction.DefaultAdapter) *PriorityNonceMempool[int64] {
return NewPriorityMempool(DefaultPriorityNonceMempoolConfig(), extractor)
}

// NextSenderTx returns the next transaction for a given sender by nonce order,
Expand Down Expand Up @@ -213,18 +215,18 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error
return nil
}

sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
signers, err := mp.signerExtractor.GetSigners(tx)
if err != nil {
return err
}
if len(sigs) == 0 {
if len(signers) == 0 {
return fmt.Errorf("tx must have at least one signer")
}

sig := sigs[0]
sender := sdk.AccAddress(sig.PubKey.Address()).String()
signer := signers[0]
sender := signer.Signer.String()
priority := mp.cfg.TxPriority.GetTxPriority(ctx, tx)
nonce := sig.Sequence
nonce := signer.Sequence
key := txMeta[C]{nonce: nonce, priority: priority, sender: sender}

senderIndex, ok := mp.senderIndices[sender]
Expand Down Expand Up @@ -427,16 +429,16 @@ func (mp *PriorityNonceMempool[C]) CountTx() int {
// Remove removes a transaction from the mempool in O(log n) time, returning an
// error if unsuccessful.
func (mp *PriorityNonceMempool[C]) Remove(tx sdk.Tx) error {
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
signers, err := mp.signerExtractor.GetSigners(tx)
if err != nil {
return err
}
if len(sigs) == 0 {
if len(signers) == 0 {
return fmt.Errorf("attempted to remove a tx with no signatures")
}

sig := sigs[0]
sender := sdk.AccAddress(sig.PubKey.Address()).String()
sig := signers[0]
sender := sig.Signer.String()
nonce := sig.Sequence

scoreKey := txMeta[C]{nonce: nonce, sender: sender}
Expand Down
Loading

0 comments on commit 2bb89fd

Please sign in to comment.