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 sendrestrictions per coin #25

Merged
merged 5 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
16 changes: 10 additions & 6 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type (
// particular, if a module changed the substore key name (or removed a substore)
// between two versions of the software.
StoreLoader func(ms storetypes.CommitMultiStore) error

contextKeyT string
)

const (
Expand All @@ -54,6 +56,8 @@ const (
execModeVoteExtension // Extend or verify a pre-commit vote
execModeVerifyVoteExtension // Verify a vote extension
execModeFinalize // Finalize a block proposal

DoNotFailFastSendContextKey contextKeyT = "DoNotFailFast"
)

var _ servertypes.ABCI = (*BaseApp)(nil)
Expand Down Expand Up @@ -708,7 +712,7 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context

func (app *BaseApp) preBlock(req *abci.RequestFinalizeBlock) error {
if app.preBlocker != nil {
ctx := app.finalizeBlockState.Context()
ctx := app.finalizeBlockState.Context().WithValue(DoNotFailFastSendContextKey, struct{}{})
rsp, err := app.preBlocker(ctx, req)
if err != nil {
return err
Expand All @@ -733,7 +737,8 @@ func (app *BaseApp) beginBlock(req *abci.RequestFinalizeBlock) (sdk.BeginBlock,
)

if app.beginBlocker != nil {
resp, err = app.beginBlocker(app.finalizeBlockState.Context())
ctx := app.finalizeBlockState.Context().WithValue(DoNotFailFastSendContextKey, struct{}{})
resp, err = app.beginBlocker(ctx)
if err != nil {
return resp, err
}
Expand All @@ -746,7 +751,6 @@ func (app *BaseApp) beginBlock(req *abci.RequestFinalizeBlock) (sdk.BeginBlock,
)
}

ctx := app.finalizeBlockState.ctx
app.AddStreamEvents(ctx.BlockHeight(), ctx.BlockTime(), resp.Events, true)

resp.Events = sdk.MarkEventsToIndex(resp.Events, app.indexEvents)
Expand Down Expand Up @@ -797,11 +801,12 @@ func (app *BaseApp) deliverTx(tx []byte) *abci.ExecTxResult {

// endBlock is an application-defined function that is called after transactions
// have been processed in FinalizeBlock.
func (app *BaseApp) endBlock(ctx context.Context) (sdk.EndBlock, error) {
func (app *BaseApp) endBlock(_ context.Context) (sdk.EndBlock, error) {
var endblock sdk.EndBlock

if app.endBlocker != nil {
eb, err := app.endBlocker(app.finalizeBlockState.Context())
ctx := app.finalizeBlockState.Context().WithValue(DoNotFailFastSendContextKey, struct{}{})
eb, err := app.endBlocker(ctx)
if err != nil {
return endblock, err
}
Expand All @@ -814,7 +819,6 @@ func (app *BaseApp) endBlock(ctx context.Context) (sdk.EndBlock, error) {
)
}

ctx := app.finalizeBlockState.ctx
app.AddStreamEvents(ctx.BlockHeight(), ctx.BlockTime(), eb.Events, true)

eb.Events = sdk.MarkEventsToIndex(eb.Events, app.indexEvents)
Expand Down
89 changes: 39 additions & 50 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,22 +157,23 @@ func (k BaseSendKeeper) InputOutputCoins(ctx context.Context, input types.Input,
return err
}

outAddresses := make([]sdk.AccAddress, len(outputs))
for i, out := range outputs {
for _, out := range outputs {
outAddress, err := k.ak.AddressCodec().StringToBytes(out.Address)
if err != nil {
return err
}

outAddresses[i], err = k.sendRestriction.apply(ctx, inAddress, outAddress, out.Coins)
if err != nil {
return err
}
}
for _, coin := range out.Coins {
newOutAddress, err := k.sendRestriction.apply(ctx, inAddress, outAddress, coin)
if err != nil {
return err
}

err = k.subUnlockedCoins(ctx, inAddress, input.Coins, true)
if err != nil {
return err
err = k.sendCoin(ctx, inAddress, newOutAddress, coin)
if err != nil {
return err
}
}
}

sdkCtx := sdk.UnwrapSDKContext(ctx)
Expand All @@ -183,30 +184,6 @@ func (k BaseSendKeeper) InputOutputCoins(ctx context.Context, input types.Input,
),
)

for i, out := range outputs {
if err := k.addCoins(ctx, outAddresses[i], out.Coins); err != nil {
return err
}

sdkCtx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeTransfer,
sdk.NewAttribute(types.AttributeKeyRecipient, outAddresses[i].String()),
sdk.NewAttribute(sdk.AttributeKeyAmount, out.Coins.String()),
),
)

// Create account if recipient does not exist.
//
// NOTE: This should ultimately be removed in favor a more flexible approach
// such as delegated fee messages.
accExists := k.ak.HasAccount(ctx, outAddresses[i])
if !accExists {
defer telemetry.IncrCounter(1, "new", "account")
k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, outAddresses[i]))
}
}

return nil
}

Expand All @@ -217,17 +194,36 @@ func (k BaseSendKeeper) SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccA
return err
}

toAddr, err := k.sendRestriction.apply(ctx, fromAddr, toAddr, amt)
if err != nil {
return err
for _, coin := range amt {
newToAddr, err := k.sendRestriction.apply(ctx, fromAddr, toAddr, coin)
if err != nil {
return err
}

err = k.sendCoin(ctx, fromAddr, newToAddr, coin)
if err != nil {
return err
}
}

err = k.subUnlockedCoins(ctx, fromAddr, amt, true)
sdkCtx := sdk.UnwrapSDKContext(ctx)
// bech32 encoding is expensive! Only do it once for fromAddr
fromAddrString := fromAddr.String()
sdkCtx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(types.AttributeKeySender, fromAddrString),
))

return nil
}

func (k BaseSendKeeper) sendCoin(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coin) error {
err := k.subUnlockedCoins(ctx, fromAddr, sdk.NewCoins(amt), true) // only sub this coin
if err != nil {
return err
}

err = k.addCoins(ctx, toAddr, amt)
err = k.addCoins(ctx, toAddr, sdk.NewCoins(amt))
if err != nil {
return err
}
Expand All @@ -242,22 +238,15 @@ func (k BaseSendKeeper) SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccA
k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, toAddr))
}

// bech32 encoding is expensive! Only do it once for fromAddr
fromAddrString := fromAddr.String()
sdkCtx := sdk.UnwrapSDKContext(ctx)
sdkCtx.EventManager().EmitEvents(sdk.Events{
sdkCtx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeTransfer,
sdk.NewAttribute(types.AttributeKeyRecipient, toAddr.String()),
sdk.NewAttribute(types.AttributeKeySender, fromAddrString),
sdk.NewAttribute(types.AttributeKeySender, fromAddr.String()),
sdk.NewAttribute(sdk.AttributeKeyAmount, amt.String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(types.AttributeKeySender, fromAddrString),
),
})

)
return nil
}

Expand Down Expand Up @@ -529,7 +518,7 @@ func (r *sendRestriction) clear() {
var _ types.SendRestrictionFn = (*sendRestriction)(nil).apply

// apply applies the send restriction if there is one. If not, it's a no-op.
func (r *sendRestriction) apply(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
func (r *sendRestriction) apply(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coin) (sdk.AccAddress, error) {
if r == nil || r.fn == nil {
return toAddr, nil
}
Expand Down
6 changes: 3 additions & 3 deletions x/bank/types/restrictions.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ func ComposeMintingRestrictions(restrictions ...MintingRestrictionFn) MintingRes
}

// A SendRestrictionFn can restrict sends and/or provide a new receiver address.
type SendRestrictionFn func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (newToAddr sdk.AccAddress, err error)
type SendRestrictionFn func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coin) (newToAddr sdk.AccAddress, err error)

// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (SendRestrictionFn) IsOnePerModuleType() {}

var _ SendRestrictionFn = NoOpSendRestrictionFn

// NoOpSendRestrictionFn is a no-op SendRestrictionFn.
func NoOpSendRestrictionFn(_ context.Context, _, toAddr sdk.AccAddress, _ sdk.Coins) (sdk.AccAddress, error) {
func NoOpSendRestrictionFn(_ context.Context, _, toAddr sdk.AccAddress, _ sdk.Coin) (sdk.AccAddress, error) {
return toAddr, nil
}

Expand Down Expand Up @@ -89,7 +89,7 @@ func ComposeSendRestrictions(restrictions ...SendRestrictionFn) SendRestrictionF
case 1:
return toRun[0]
}
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) {
return func(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coin) (sdk.AccAddress, error) {
var err error
for _, r := range toRun {
toAddr, err = r(ctx, fromAddr, toAddr, amt)
Expand Down
3 changes: 2 additions & 1 deletion x/gov/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) error {
// Messages may mutate state thus we use a cached context. If one of
// the handlers fails, no state mutation is written and the error
// message is logged.
cacheCtx, writeCache := ctx.CacheContext()
execCtx := ctx.WithValue(baseapp.DoNotFailFastSendContextKey, nil) // enable fail fast during msg handling
cacheCtx, writeCache := execCtx.CacheContext()
messages, err := proposal.GetMsgs()
if err != nil {
proposal.Status = v1.StatusFailed
Expand Down
Loading