Skip to content

Commit

Permalink
Merge pull request #25 from InjectiveLabs/feat-sendrestrictions-per-coin
Browse files Browse the repository at this point in the history
Feat sendrestrictions per coin
  • Loading branch information
albertchon authored Jun 14, 2024
2 parents fc7ff68 + b0d018a commit 2ef735e
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 60 deletions.
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

0 comments on commit 2ef735e

Please sign in to comment.