Skip to content

Commit

Permalink
feat(vbank): new param allowed_monitoring_accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Nov 15, 2024
1 parent 1682675 commit 00930fc
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 18 deletions.
7 changes: 7 additions & 0 deletions golang/cosmos/proto/agoric/vbank/vbank.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ message Params {
int64 reward_smoothing_blocks = 3 [
(gogoproto.moretags) = "yaml:\"reward_smoothing_blocks\""
];

// allowed_monitoring_accounts is an array of account addresses that can be
// monitored for sends and receives. An element of `"*"` will permit any
// address. An element of `"!"` will deny all addresses.
repeated string allowed_monitoring_accounts = 4 [
(gogoproto.moretags) = "yaml:\"allowed_monitoring_accounts\""
];
}

// The current state of the module.
Expand Down
7 changes: 6 additions & 1 deletion golang/cosmos/x/vbank/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ entirely at the ERTP level.

- `feeCollectorName`: the module which handles fee distribution to stakers.
- `reward_epoch_duration_blocks`: the duration (in blocks) over which fees should be given to the fee collector.
- `per_epoch_reward_fraction`: a decimal of how much of the `GiveawayPool` is paid as validator rewards per epoch
- `allowed_monitoring_accounts`: an array of account addresses that can be
monitored for sends and receives, defaulting to
`[authtypes.NewModuleAddress(types.ProvisionPoolName)]`. An element of `"*"`
will permit any address. An element of `"!"` will deny all addresses.

## State

Expand All @@ -22,7 +27,7 @@ The Vbank module maintains no significant state, but will access stored state th

Purse operations which change the balance result in a downcall to this module to update the underlying account. A downcall is also made to query the account balance.

Upon an `EndBlock()` call, the module will scan the block for all `MsgSend` and `MsgMultiSend` events (see `cosmos-sdk/x/bank/spec/04_events.md`) and perform a `VBANK_BALANCE_UPDATE` upcall for all denominations held in *only the mentioned module accounts*.
Upon an `EndBlock()` call, the module will scan the block for all `MsgSend` and `MsgMultiSend` events (see `cosmos-sdk/x/bank/spec/04_events.md`) and perform a `VBANK_BALANCE_UPDATE` upcall for all denominations held in *only in the allowed_monitoring_accounts*.

The following fields are common to the Vbank messages:
- `"address"`, `"recipient"`, `"sender"`: account address as a bech32-encoded string
Expand Down
11 changes: 3 additions & 8 deletions golang/cosmos/x/vbank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/Agoric/agoric-sdk/golang/cosmos/x/vbank/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"

vm "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
Expand Down Expand Up @@ -88,13 +87,9 @@ func (k Keeper) GetModuleAccountAddress(ctx sdk.Context, name string) sdk.AccAdd
return acct.GetAddress()
}

func (k Keeper) IsModuleAccount(ctx sdk.Context, addr sdk.AccAddress) bool {
acc := k.accountKeeper.GetAccount(ctx, addr)
if acc == nil {
return false
}
_, ok := acc.(authtypes.ModuleAccountI)
return ok
func (k Keeper) IsAllowedMonitoringAccount(ctx sdk.Context, addr sdk.AccAddress) bool {
params := k.GetParams(ctx)
return params.IsAllowedMonitoringAccount(addr.String())
}

func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
Expand Down
2 changes: 1 addition & 1 deletion golang/cosmos/x/vbank/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ NextEvent:
addressToUpdate = make(map[string]sdk.Coins, len(addressToUpdate))
for addr, denoms := range unfilteredAddresses {
accAddr, err := sdk.AccAddressFromBech32(addr)
if err == nil && am.keeper.IsModuleAccount(ctx, accAddr) {
if err == nil && am.keeper.IsAllowedMonitoringAccount(ctx, accAddr) {
// Pass through the module account.
addressToUpdate[addr] = denoms
}
Expand Down
60 changes: 59 additions & 1 deletion golang/cosmos/x/vbank/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,31 @@ import (
yaml "gopkg.in/yaml.v2"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)

const AllowAllMonitoringAccountsPattern = "*"
const DenyAllMonitoringAccountsPattern = "!"

// Parameter keys
var (
ParamStoreKeyRewardEpochDurationBlocks = []byte("reward_epoch_duration_blocks")
ParamStoreKeyRewardSmoothingBlocks = []byte("reward_smoothing_blocks")
ParamStoreKeyPerEpochRewardFraction = []byte("per_epoch_reward_fraction")
ParamStoreKeyAllowedMonitoringAccounts = []byte("allowed_monitoring_accounts")
)

var cachedDefaultAllowed []string

// DefaultAllowedMonitoringAccounts returns the default allowed monitoring accounts.
func DefaultAllowedMonitoringAccounts() []string {
if cachedDefaultAllowed == nil {
cachedDefaultAllowed = []string{authtypes.NewModuleAddress(ProvisionPoolName).String()}
}
return cachedDefaultAllowed
}

// ParamKeyTable returns the parameter key table.
func ParamKeyTable() paramtypes.KeyTable {
return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
Expand All @@ -27,6 +42,7 @@ func DefaultParams() Params {
RewardEpochDurationBlocks: 0,
RewardSmoothingBlocks: 1,
PerEpochRewardFraction: sdk.OneDec(),
AllowedMonitoringAccounts: DefaultAllowedMonitoringAccounts(),
}
}

Expand Down Expand Up @@ -67,12 +83,34 @@ func (p Params) RewardRate(pool sdk.Coins, blocks int64) sdk.Coins {
return sdk.NewCoins(coins...)
}

// IsAllowedMonitoringAccount checks to see if a given address is allowed to monitor its balance.
func (p Params) IsAllowedMonitoringAccount(addr string) bool {
allowed := p.AllowedMonitoringAccounts
if len(allowed) == 0 {
allowed = DefaultAllowedMonitoringAccounts()
}

for _, pat := range allowed {
switch pat {
case AllowAllMonitoringAccountsPattern:
return true
case DenyAllMonitoringAccountsPattern:
return false
case addr:
return true
}
}

return false
}

// ParamSetPairs returns the parameter set pairs.
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(ParamStoreKeyRewardEpochDurationBlocks, &p.RewardEpochDurationBlocks, validateRewardEpochDurationBlocks),
paramtypes.NewParamSetPair(ParamStoreKeyRewardSmoothingBlocks, &p.RewardSmoothingBlocks, validateRewardSmoothingBlocks),
paramtypes.NewParamSetPair(ParamStoreKeyPerEpochRewardFraction, &p.PerEpochRewardFraction, validatePerEpochRewardFraction),
paramtypes.NewParamSetPair(ParamStoreKeyAllowedMonitoringAccounts, &p.AllowedMonitoringAccounts, validateAllowedMonitoringAccounts),
}
}

Expand All @@ -84,7 +122,12 @@ func (p Params) ValidateBasic() error {
if err := validatePerEpochRewardFraction(p.PerEpochRewardFraction); err != nil {
return err
}

if err := validateRewardSmoothingBlocks(p.RewardSmoothingBlocks); err != nil {
return err
}
if err := validateAllowedMonitoringAccounts(p.AllowedMonitoringAccounts); err != nil {
return err
}
return nil
}

Expand Down Expand Up @@ -130,3 +173,18 @@ func validatePerEpochRewardFraction(i interface{}) error {

return nil
}

func validateAllowedMonitoringAccounts(i interface{}) error {
v, ok := i.([]string)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

for a, acc := range v {
if acc == "" {
return fmt.Errorf("allowed monitoring accounts element[%d] cannot be empty", a)
}
}

return nil
}
19 changes: 12 additions & 7 deletions golang/cosmos/x/vbank/vbank_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ func Test_Receive_GiveToRewardDistributor(t *testing.T) {
params := types.DefaultParams()
params.RewardEpochDurationBlocks = 0
params.RewardSmoothingBlocks = tt.duration
params.AllowedMonitoringAccounts = []string{"*"}

keeper.SetParams(ctx, params)
keeper.SetState(ctx, types.State{RewardPool: tt.rewardPool})
Expand Down Expand Up @@ -524,7 +525,7 @@ func Test_EndBlock_Events(t *testing.T) {
}
keeper, ctx := makeTestKit(acct, bank)
// Turn off rewards.
keeper.SetParams(ctx, types.Params{PerEpochRewardFraction: sdk.ZeroDec()})
keeper.SetParams(ctx, types.Params{PerEpochRewardFraction: sdk.ZeroDec(), AllowedMonitoringAccounts: []string{"*"}})
msgsSent := []string{}
keeper.PushAction = func(ctx sdk.Context, action vm.Action) error {
bz, err := json.Marshal(action)
Expand Down Expand Up @@ -804,15 +805,19 @@ func Test_Module_Account(t *testing.T) {
}

modAddr := sdk.MustAccAddressFromBech32(moduleBech32)
if !keeper.IsModuleAccount(ctx, modAddr) {
t.Errorf("got IsModuleAccount modAddr = false, want true")
if keeper.IsAllowedMonitoringAccount(ctx, modAddr) {
t.Errorf("got IsAllowedMonitoringAccount modAddr = true, want false")
}
provisionPool := authtypes.NewModuleAddress("vbank/provision")
if !keeper.IsAllowedMonitoringAccount(ctx, provisionPool) {
t.Errorf("got IsAllowedMonitoringAccount provisionPool = false, want true")
}
notModAddr := sdk.MustAccAddressFromBech32(addr1)
if keeper.IsModuleAccount(ctx, notModAddr) {
t.Errorf("got IsModuleAccount notModAddr = true, want false")
if keeper.IsAllowedMonitoringAccount(ctx, notModAddr) {
t.Errorf("got IsAllowedMonitoringAccount notModAddr = true, want false")
}
missingAddr := sdk.MustAccAddressFromBech32(addr2)
if keeper.IsModuleAccount(ctx, missingAddr) {
t.Errorf("got IsModuleAccount missingAddr = false, want true")
if keeper.IsAllowedMonitoringAccount(ctx, missingAddr) {
t.Errorf("got IsAllowedMonitoringAccount missingAddr = false, want true")
}
}

0 comments on commit 00930fc

Please sign in to comment.