Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x/accounts): add event emission to accounts module #19636

Merged
merged 8 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
19 changes: 10 additions & 9 deletions x/accounts/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/x/accounts/accountstd"
"cosmossdk.io/x/accounts/internal/implementation"
)
Expand All @@ -26,7 +27,7 @@ type TestAccount struct {
}

func (t TestAccount) RegisterInitHandler(builder *implementation.InitBuilder) {
implementation.RegisterInitHandler(builder, func(ctx context.Context, _ *types.Empty) (*types.Empty, error) {
implementation.RegisterInitHandler(builder, func(ctx context.Context, _ appmodule.Environment, _ *types.Empty) (*types.Empty, error) {
// we also force a module call here to test things work as expected.
_, err := implementation.QueryModule[bankv1beta1.QueryBalanceResponse](ctx, &bankv1beta1.QueryBalanceRequest{
Address: string(implementation.Whoami(ctx)),
Expand All @@ -37,11 +38,11 @@ func (t TestAccount) RegisterInitHandler(builder *implementation.InitBuilder) {
}

func (t TestAccount) RegisterExecuteHandlers(builder *implementation.ExecuteBuilder) {
implementation.RegisterExecuteHandler(builder, func(_ context.Context, _ *types.Empty) (*types.Empty, error) {
implementation.RegisterExecuteHandler(builder, func(_ context.Context, _ appmodule.Environment, _ *types.Empty) (*types.Empty, error) {
return &types.Empty{}, nil
})

implementation.RegisterExecuteHandler(builder, func(_ context.Context, req *types.StringValue) (*types.UInt64Value, error) {
implementation.RegisterExecuteHandler(builder, func(_ context.Context, _ appmodule.Environment, req *types.StringValue) (*types.UInt64Value, error) {
value, err := strconv.ParseUint(req.Value, 10, 64)
if err != nil {
return nil, err
Expand All @@ -51,7 +52,7 @@ func (t TestAccount) RegisterExecuteHandlers(builder *implementation.ExecuteBuil
})

// this is for intermodule comms testing, we simulate a bank send
implementation.RegisterExecuteHandler(builder, func(ctx context.Context, req *types.Int64Value) (*types.Empty, error) {
implementation.RegisterExecuteHandler(builder, func(ctx context.Context, _ appmodule.Environment, req *types.Int64Value) (*types.Empty, error) {
resp, err := implementation.ExecModule[bankv1beta1.MsgSendResponse](ctx, &bankv1beta1.MsgSend{
FromAddress: string(implementation.Whoami(ctx)),
ToAddress: "recipient",
Expand All @@ -73,23 +74,23 @@ func (t TestAccount) RegisterExecuteHandlers(builder *implementation.ExecuteBuil
})

// genesis testing
implementation.RegisterExecuteHandler(builder, func(ctx context.Context, req *types.UInt64Value) (*types.Empty, error) {
implementation.RegisterExecuteHandler(builder, func(ctx context.Context, _ appmodule.Environment, req *types.UInt64Value) (*types.Empty, error) {
return &types.Empty{}, t.Counter.Set(ctx, req.Value)
})
}

func (t TestAccount) RegisterQueryHandlers(builder *implementation.QueryBuilder) {
implementation.RegisterQueryHandler(builder, func(_ context.Context, _ *types.Empty) (*types.Empty, error) {
implementation.RegisterQueryHandler(builder, func(_ context.Context, _ appmodule.Environment, _ *types.Empty) (*types.Empty, error) {
return &types.Empty{}, nil
})

implementation.RegisterQueryHandler(builder, func(_ context.Context, req *types.UInt64Value) (*types.StringValue, error) {
implementation.RegisterQueryHandler(builder, func(_ context.Context, _ appmodule.Environment, req *types.UInt64Value) (*types.StringValue, error) {
return &types.StringValue{Value: strconv.FormatUint(req.Value, 10)}, nil
})

// test intermodule comms, we simulate someone is sending the account a request for the accounts balance
// of a given denom.
implementation.RegisterQueryHandler(builder, func(ctx context.Context, req *types.StringValue) (*types.Int64Value, error) {
implementation.RegisterQueryHandler(builder, func(ctx context.Context, _ appmodule.Environment, req *types.StringValue) (*types.Int64Value, error) {
resp, err := implementation.QueryModule[bankv1beta1.QueryBalanceResponse](ctx, &bankv1beta1.QueryBalanceRequest{
Address: string(implementation.Whoami(ctx)),
Denom: req.Value,
Expand All @@ -107,7 +108,7 @@ func (t TestAccount) RegisterQueryHandlers(builder *implementation.QueryBuilder)

// genesis testing; DoubleValue does not make sense as a request type for this query, but empty is already taken
// and this is only used for testing.
implementation.RegisterQueryHandler(builder, func(ctx context.Context, _ *types.DoubleValue) (*types.UInt64Value, error) {
implementation.RegisterQueryHandler(builder, func(ctx context.Context, _ appmodule.Environment, _ *types.DoubleValue) (*types.UInt64Value, error) {
v, err := t.Counter.Peek(ctx)
if err != nil {
return nil, err
Expand Down
7 changes: 4 additions & 3 deletions x/accounts/accountstd/exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"fmt"

"cosmossdk.io/core/appmodule"
"cosmossdk.io/x/accounts/internal/implementation"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -34,23 +35,23 @@ type Dependencies = implementation.Dependencies

func RegisterExecuteHandler[
Req any, ProtoReq implementation.ProtoMsgG[Req], Resp any, ProtoResp implementation.ProtoMsgG[Resp],
](router *ExecuteBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error),
](router *ExecuteBuilder, handler func(ctx context.Context, env appmodule.Environment, req ProtoReq) (ProtoResp, error),
) {
implementation.RegisterExecuteHandler(router, handler)
}

// RegisterQueryHandler registers a query handler for a smart account that uses protobuf.
func RegisterQueryHandler[
Req any, ProtoReq implementation.ProtoMsgG[Req], Resp any, ProtoResp implementation.ProtoMsgG[Resp],
](router *QueryBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error),
](router *QueryBuilder, handler func(ctx context.Context, env appmodule.Environment, req ProtoReq) (ProtoResp, error),
) {
implementation.RegisterQueryHandler(router, handler)
}

// RegisterInitHandler registers an initialisation handler for a smart account that uses protobuf.
func RegisterInitHandler[
Req any, ProtoReq implementation.ProtoMsgG[Req], Resp any, ProtoResp implementation.ProtoMsgG[Resp],
](router *InitBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error),
](router *InitBuilder, handler func(ctx context.Context, env appmodule.Environment, req ProtoReq) (ProtoResp, error),
) {
implementation.RegisterInitHandler(router, handler)
}
Expand Down
9 changes: 5 additions & 4 deletions x/accounts/defaults/base/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
"cosmossdk.io/collections"
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/header"
"cosmossdk.io/x/accounts/accountstd"
v1 "cosmossdk.io/x/accounts/defaults/base/v1"
Expand Down Expand Up @@ -54,11 +55,11 @@ type Account struct {
signingHandlers *signing.HandlerMap
}

func (a Account) Init(ctx context.Context, msg *v1.MsgInit) (*v1.MsgInitResponse, error) {
func (a Account) Init(ctx context.Context, _ appmodule.Environment, msg *v1.MsgInit) (*v1.MsgInitResponse, error) {
return &v1.MsgInitResponse{}, a.verifyAndSetPubKey(ctx, msg.PubKey)
}

func (a Account) SwapPubKey(ctx context.Context, msg *v1.MsgSwapPubKey) (*v1.MsgSwapPubKeyResponse, error) {
func (a Account) SwapPubKey(ctx context.Context, _ appmodule.Environment, msg *v1.MsgSwapPubKey) (*v1.MsgSwapPubKeyResponse, error) {
if !accountstd.SenderIsSelf(ctx) {
return nil, errors.New("unauthorized")
}
Expand All @@ -75,7 +76,7 @@ func (a Account) verifyAndSetPubKey(ctx context.Context, key []byte) error {
}

// Authenticate implements the authentication flow of an abstracted base account.
func (a Account) Authenticate(ctx context.Context, msg *aa_interface_v1.MsgAuthenticate) (*aa_interface_v1.MsgAuthenticateResponse, error) {
func (a Account) Authenticate(ctx context.Context, _ appmodule.Environment, msg *aa_interface_v1.MsgAuthenticate) (*aa_interface_v1.MsgAuthenticateResponse, error) {
if !accountstd.SenderIsAccountsModule(ctx) {
return nil, errors.New("unauthorized: only accounts module is allowed to call this")
}
Expand Down Expand Up @@ -195,7 +196,7 @@ func (a Account) getTxData(msg *aa_interface_v1.MsgAuthenticate) (signing.TxData
}, nil
}

func (a Account) QuerySequence(ctx context.Context, _ *v1.QuerySequence) (*v1.QuerySequenceResponse, error) {
func (a Account) QuerySequence(ctx context.Context, _ appmodule.Environment, _ *v1.QuerySequence) (*v1.QuerySequenceResponse, error) {
seq, err := a.Sequence.Peek(ctx)
if err != nil {
return nil, err
Expand Down
13 changes: 7 additions & 6 deletions x/accounts/internal/implementation/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/cosmos/gogoproto/types"

"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule"
)

var _ Account = (*TestAccount)(nil)
Expand All @@ -25,31 +26,31 @@ type TestAccount struct {
}

func (TestAccount) RegisterInitHandler(builder *InitBuilder) {
RegisterInitHandler(builder, func(_ context.Context, req *types.StringValue) (*types.StringValue, error) {
RegisterInitHandler(builder, func(_ context.Context, _ appmodule.Environment, req *types.StringValue) (*types.StringValue, error) {
return &types.StringValue{Value: req.Value + "init-echo"}, nil
})
}

func (t TestAccount) RegisterExecuteHandlers(builder *ExecuteBuilder) {
RegisterExecuteHandler(builder, func(_ context.Context, req *types.StringValue) (*types.StringValue, error) {
RegisterExecuteHandler(builder, func(_ context.Context, env appmodule.Environment, req *types.StringValue) (*types.StringValue, error) {
return &types.StringValue{Value: req.Value + "execute-echo"}, nil
})

RegisterExecuteHandler(builder, func(_ context.Context, req *types.BytesValue) (*types.BytesValue, error) {
RegisterExecuteHandler(builder, func(_ context.Context, env appmodule.Environment, req *types.BytesValue) (*types.BytesValue, error) {
return &types.BytesValue{Value: append(req.Value, "bytes-execute-echo"...)}, nil
})

// State tester
RegisterExecuteHandler(builder, func(ctx context.Context, req *types.UInt64Value) (*types.Empty, error) {
RegisterExecuteHandler(builder, func(ctx context.Context, env appmodule.Environment, req *types.UInt64Value) (*types.Empty, error) {
return &types.Empty{}, t.Item.Set(ctx, req.Value)
})
}

func (t TestAccount) RegisterQueryHandlers(builder *QueryBuilder) {
RegisterQueryHandler(builder, func(_ context.Context, req *types.StringValue) (*types.StringValue, error) {
RegisterQueryHandler(builder, func(_ context.Context, env appmodule.Environment, req *types.StringValue) (*types.StringValue, error) {
return &types.StringValue{Value: req.Value + "query-echo"}, nil
})
RegisterQueryHandler(builder, func(_ context.Context, req *types.BytesValue) (*types.BytesValue, error) {
RegisterQueryHandler(builder, func(_ context.Context, env appmodule.Environment, req *types.BytesValue) (*types.BytesValue, error) {
return &types.BytesValue{Value: append(req.Value, "bytes-query-echo"...)}, nil
})
}
20 changes: 11 additions & 9 deletions x/accounts/internal/implementation/api_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"errors"
"fmt"

"cosmossdk.io/core/appmodule"
)

var (
Expand All @@ -22,15 +24,15 @@ type InitBuilder struct {
// handler is the handler function that will be called when the smart account is initialized.
// Although the function here is defined to take an any, the smart account will work
// with a typed version of it.
handler func(ctx context.Context, initRequest ProtoMsg) (initResponse ProtoMsg, err error)
handler func(ctx context.Context, env appmodule.Environment, initRequest ProtoMsg) (initResponse ProtoMsg, err error)

// schema is the schema of the message that will be passed to the handler function.
schema HandlerSchema
}

// makeHandler returns the handler function that will be called when the smart account is initialized.
// It returns an error if no handler was registered.
func (i *InitBuilder) makeHandler() (func(ctx context.Context, initRequest ProtoMsg) (initResponse ProtoMsg, err error), error) {
func (i *InitBuilder) makeHandler() (func(ctx context.Context, env appmodule.Environment, initRequest ProtoMsg) (initResponse ProtoMsg, err error), error) {
if i.handler == nil {
return nil, errNoInitHandler
}
Expand All @@ -40,7 +42,7 @@ func (i *InitBuilder) makeHandler() (func(ctx context.Context, initRequest Proto
// NewExecuteBuilder creates a new ExecuteBuilder instance.
func NewExecuteBuilder() *ExecuteBuilder {
return &ExecuteBuilder{
handlers: make(map[string]func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error)),
handlers: make(map[string]func(ctx context.Context, env appmodule.Environment, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error)),
handlersSchema: make(map[string]HandlerSchema),
}
}
Expand All @@ -49,7 +51,7 @@ func NewExecuteBuilder() *ExecuteBuilder {
// to a handler function for a specific account.
type ExecuteBuilder struct {
// handlers is a map of handler functions that will be called when the smart account is executed.
handlers map[string]func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error)
handlers map[string]func(ctx context.Context, env appmodule.Environment, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error)

// handlersSchema is a map of schemas for the messages that will be passed to the handler functions
// and the messages that will be returned by the handler functions.
Expand All @@ -59,10 +61,10 @@ type ExecuteBuilder struct {
err error
}

func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error), error) {
func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, env appmodule.Environment, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error), error) {
// if no handler is registered it's fine, it means the account will not be accepting execution or query messages.
if len(r.handlers) == 0 {
return func(ctx context.Context, _ ProtoMsg) (_ ProtoMsg, err error) {
return func(ctx context.Context, _ appmodule.Environment, _ ProtoMsg) (_ ProtoMsg, err error) {
return nil, errNoExecuteHandler
}, nil
}
Expand All @@ -72,13 +74,13 @@ func (r *ExecuteBuilder) makeHandler() (func(ctx context.Context, executeRequest
}

// build the real execution handler
return func(ctx context.Context, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error) {
return func(ctx context.Context, env appmodule.Environment, executeRequest ProtoMsg) (executeResponse ProtoMsg, err error) {
messageName := MessageName(executeRequest)
handler, ok := r.handlers[messageName]
if !ok {
return nil, fmt.Errorf("%w: no handler for message %s", errInvalidMessage, messageName)
}
return handler(ctx, executeRequest)
return handler(ctx, env, executeRequest)
}, nil
}

Expand All @@ -96,7 +98,7 @@ type QueryBuilder struct {
er *ExecuteBuilder
}

func (r *QueryBuilder) makeHandler() (func(ctx context.Context, queryRequest ProtoMsg) (queryResponse ProtoMsg, err error), error) {
func (r *QueryBuilder) makeHandler() (func(ctx context.Context, env appmodule.Environment, queryRequest ProtoMsg) (queryResponse ProtoMsg, err error), error) {
return r.er.makeHandler()
}

Expand Down
14 changes: 10 additions & 4 deletions x/accounts/internal/implementation/api_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import (
"context"
"testing"

"cosmossdk.io/core/appmodule"
"github.com/cosmos/gogoproto/types"
"github.com/stretchr/testify/require"
)

func TestRouterDoubleRegistration(t *testing.T) {
router := NewExecuteBuilder()
RegisterExecuteHandler(router, func(_ context.Context, req *types.StringValue) (*types.StringValue, error) { return nil, nil })
RegisterExecuteHandler(router, func(_ context.Context, req *types.StringValue) (*types.StringValue, error) { return nil, nil })
RegisterExecuteHandler(router, func(_ context.Context, env appmodule.Environment, req *types.StringValue) (*types.StringValue, error) {
return nil, nil
})
RegisterExecuteHandler(router, func(_ context.Context, env appmodule.Environment, req *types.StringValue) (*types.StringValue, error) {
return nil, nil
})

_, err := router.makeHandler()
require.ErrorContains(t, err, "already registered")
Expand All @@ -28,8 +33,9 @@ func TestEmptyQueryExecuteHandler(t *testing.T) {

ctx := context.Background()

_, err = qh(ctx, &types.StringValue{})
env := appmodule.Environment{}
_, err = qh(ctx, env, &types.StringValue{})
require.ErrorIs(t, err, errNoExecuteHandler)
_, err = eh(ctx, &types.StringValue{})
_, err = eh(ctx, env, &types.StringValue{})
require.ErrorIs(t, err, errNoExecuteHandler)
}
4 changes: 3 additions & 1 deletion x/accounts/internal/implementation/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"cosmossdk.io/collections"
"cosmossdk.io/collections/colltest"
"cosmossdk.io/core/appmodule"
)

func TestMakeAccountContext(t *testing.T) {
Expand All @@ -31,7 +32,8 @@ func TestMakeAccountContext(t *testing.T) {
impl, err := newImplementation(sb, ta)
require.NoError(t, err)

_, err = impl.Execute(accountCtx, &types.UInt64Value{Value: 1000})
env := appmodule.Environment{}
_, err = impl.Execute(accountCtx, env, &types.UInt64Value{Value: 1000})
require.NoError(t, err)

// we want to ensure that the account wrote in the correct prefix.
Expand Down
7 changes: 4 additions & 3 deletions x/accounts/internal/implementation/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"cosmossdk.io/collections"
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/gas"
"cosmossdk.io/core/header"

Expand Down Expand Up @@ -111,11 +112,11 @@ func newImplementation(schemaBuilder *collections.SchemaBuilder, account Account
// and non-generic implementation usable by the x/accounts module.
type Implementation struct {
// Init defines the initialisation handler for the smart account.
Init func(ctx context.Context, msg ProtoMsg) (resp ProtoMsg, err error)
Init func(ctx context.Context, env appmodule.Environment, msg ProtoMsg) (resp ProtoMsg, err error)
// Execute defines the execution handler for the smart account.
Execute func(ctx context.Context, msg ProtoMsg) (resp ProtoMsg, err error)
Execute func(ctx context.Context, env appmodule.Environment, msg ProtoMsg) (resp ProtoMsg, err error)
// Query defines the query handler for the smart account.
Query func(ctx context.Context, msg ProtoMsg) (resp ProtoMsg, err error)
Query func(ctx context.Context, env appmodule.Environment, msg ProtoMsg) (resp ProtoMsg, err error)
// CollectionsSchema represents the state schema.
CollectionsSchema collections.Schema
// InitHandlerSchema represents the init handler schema.
Expand Down
Loading
Loading