Skip to content

Commit

Permalink
feat(x/swingset): Add parameters for controlling vat cleanup budget
Browse files Browse the repository at this point in the history
Ref #8928
  • Loading branch information
gibson042 committed Nov 9, 2024
1 parent 02c06c4 commit b8b18cc
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 12 deletions.
25 changes: 25 additions & 0 deletions golang/cosmos/proto/agoric/swingset/swingset.proto
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ message Params {
repeated QueueSize queue_max = 5 [
(gogoproto.nullable) = false
];

// Vat cleanup budget values.
// These values are used by SwingSet to control the pace of removing data
// associated with a terminated vat as described at
// https://github.com/Agoric/agoric-sdk/blob/master/packages/SwingSet/docs/run-policy.md#terminated-vat-cleanup
//
// There is no required order to this list of entries, but all the chain
// nodes must all serialize and deserialize the existing order without
// permuting it.
repeated UintMapEntry vat_cleanup_budget = 6 [
(gogoproto.nullable) = false
];
}

// The current state of the module.
Expand Down Expand Up @@ -119,6 +131,7 @@ message PowerFlagFee {
}

// Map element of a string key to a size.
// TODO: Replace with UintMapEntry?
message QueueSize {
option (gogoproto.equal) = true;

Expand All @@ -129,6 +142,18 @@ message QueueSize {
int32 size = 2;
}

// Map element of a string key to an unsigned integer.
// The value uses cosmos-sdk Uint rather than a native Go type to ensure that
// zeroes survive "omitempty" JSON serialization.
message UintMapEntry {
option (gogoproto.equal) = true;
string key = 1;
string value = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint",
(gogoproto.nullable) = false
];
}

// Egress is the format for a swingset egress.
message Egress {
option (gogoproto.equal) = false;
Expand Down
32 changes: 28 additions & 4 deletions golang/cosmos/x/swingset/types/default-params.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,22 @@ const (
BeansPerXsnapComputron = "xsnapComputron"
BeansPerSmartWalletProvision = "smartWalletProvision"

// PowerFlags.
PowerFlagSmartWallet = "SMART_WALLET"

// QueueSize keys.
// Keep up-to-date with updateQueueAllowed() in packanges/cosmic-swingset/src/launch-chain.js
QueueInbound = "inbound"
QueueInboundMempool = "inbound_mempool"

// PowerFlags.
PowerFlagSmartWallet = "SMART_WALLET"
// Vat cleanup budget keys.
// Keep up-to-date with CleanupBudget in packanges/cosmic-swingset/src/launch-chain.js
VatCleanupDefault = "default"
VatCleanupExports = "exports"
VatCleanupImports = "imports"
VatCleanupKv = "kv"
VatCleanupSnapshots = "snapshots"
VatCleanupTranscripts = "transcripts"
)

var (
Expand Down Expand Up @@ -62,10 +71,25 @@ var (
}

DefaultInboundQueueMax = int32(1_000)

DefaultQueueMax = []QueueSize{
DefaultQueueMax = []QueueSize{
NewQueueSize(QueueInbound, DefaultInboundQueueMax),
}

// FIXME: Settle on default values
DefaultVatCleanupDefault = sdk.NewUint(0) // 5
DefaultVatCleanupExports = sdk.NewUint(0) // 5
DefaultVatCleanupImports = sdk.NewUint(0) // 5
DefaultVatCleanupKv = sdk.NewUint(0) // 50
DefaultVatCleanupSnapshots = sdk.NewUint(0) // 50
DefaultVatCleanupTranscripts = sdk.NewUint(0) // 50
DefaultVatCleanupBudget = []UintMapEntry{
UintMapEntry{VatCleanupDefault, DefaultVatCleanupDefault},
UintMapEntry{VatCleanupExports, DefaultVatCleanupExports},
UintMapEntry{VatCleanupImports, DefaultVatCleanupImports},
UintMapEntry{VatCleanupKv, DefaultVatCleanupKv},
UintMapEntry{VatCleanupSnapshots, DefaultVatCleanupSnapshots},
UintMapEntry{VatCleanupTranscripts, DefaultVatCleanupTranscripts},
}
)

// move DefaultBeansPerUnit to a function to allow for boot overriding of the Default params
Expand Down
50 changes: 50 additions & 0 deletions golang/cosmos/x/swingset/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var (
ParamStoreKeyFeeUnitPrice = []byte("fee_unit_price")
ParamStoreKeyPowerFlagFees = []byte("power_flag_fees")
ParamStoreKeyQueueMax = []byte("queue_max")
ParamStoreKeyVatCleanupBudget = []byte("vat_cleanup_budget")
)

func NewStringBeans(key string, beans sdkmath.Uint) StringBeans {
Expand Down Expand Up @@ -53,6 +54,7 @@ func DefaultParams() Params {
FeeUnitPrice: DefaultFeeUnitPrice,
PowerFlagFees: DefaultPowerFlagFees,
QueueMax: DefaultQueueMax,
VatCleanupBudget: DefaultVatCleanupBudget,
}
}

Expand All @@ -69,6 +71,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
paramtypes.NewParamSetPair(ParamStoreKeyBootstrapVatConfig, &p.BootstrapVatConfig, validateBootstrapVatConfig),
paramtypes.NewParamSetPair(ParamStoreKeyPowerFlagFees, &p.PowerFlagFees, validatePowerFlagFees),
paramtypes.NewParamSetPair(ParamStoreKeyQueueMax, &p.QueueMax, validateQueueMax),
paramtypes.NewParamSetPair(ParamStoreKeyVatCleanupBudget, &p.VatCleanupBudget, validateVatCleanupBudget),
}
}

Expand All @@ -89,6 +92,9 @@ func (p Params) ValidateBasic() error {
if err := validateQueueMax(p.QueueMax); err != nil {
return err
}
if err := validateVatCleanupBudget(p.VatCleanupBudget); err != nil {
return err
}

return nil
}
Expand Down Expand Up @@ -165,6 +171,14 @@ func validateQueueMax(i interface{}) error {
return nil
}

func validateVatCleanupBudget(i interface{}) error {
_, ok := i.([]UintMapEntry)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
return nil
}

// UpdateParams appends any missing params, configuring them to their defaults,
// then returning the updated params or an error. Existing params are not
// modified, regardless of their value, and they are not removed if they no
Expand All @@ -182,10 +196,15 @@ func UpdateParams(params Params) (Params, error) {
if err != nil {
return params, err
}
newVcb, err := appendMissingDefaults(params.VatCleanupBudget, DefaultVatCleanupBudget)
if err != nil {
return params, err
}

params.BeansPerUnit = newBpu
params.PowerFlagFees = newPff
params.QueueMax = newQm
params.VatCleanupBudget = newVcb
return params, nil
}

Expand Down Expand Up @@ -238,3 +257,34 @@ func appendMissingDefaultQueueSize(qs []QueueSize, defaultQs []QueueSize) ([]Que
}
return qs, nil
}

// appendMissingDefaults appends to an input list any missing entries with their
// respective default values and returns the result.
func appendMissingDefaults[Entry StringBeans | PowerFlagFee | QueueSize | UintMapEntry](entries []Entry, defaults []Entry) ([]Entry, error) {
getKey := func(entry any) string {
switch e := entry.(type) {
case StringBeans:
return e.Key
case PowerFlagFee:
return e.PowerFlag
case QueueSize:
return e.Key
case UintMapEntry:
return e.Key
}
panic("unreachable")
}

existingKeys := make(map[string]bool, len(entries))
for _, entry := range entries {
existingKeys[getKey(entry)] = true
}

for _, defaultEntry := range defaults {
if exists := existingKeys[getKey(defaultEntry)]; !exists {
entries = append(entries, defaultEntry)
}
}

return entries, nil
}
48 changes: 40 additions & 8 deletions golang/cosmos/x/swingset/types/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,59 @@ func TestAddStorageBeanCost(t *testing.T) {
}
}

func TestUpdateParams(t *testing.T) {

func TestUpdateParamsFromEmpty(t *testing.T) {
in := Params{
BeansPerUnit: []beans{},
BootstrapVatConfig: "baz",
BeansPerUnit: nil,
BootstrapVatConfig: "",
FeeUnitPrice: sdk.NewCoins(sdk.NewInt64Coin("denom", 789)),
PowerFlagFees: []PowerFlagFee{},
QueueMax: []QueueSize{},
PowerFlagFees: nil,
QueueMax: nil,
VatCleanupBudget: nil,
}
want := Params{
BeansPerUnit: DefaultBeansPerUnit(),
BootstrapVatConfig: "baz",
BootstrapVatConfig: "",
FeeUnitPrice: sdk.NewCoins(sdk.NewInt64Coin("denom", 789)),
PowerFlagFees: DefaultPowerFlagFees,
QueueMax: DefaultQueueMax,
VatCleanupBudget: DefaultVatCleanupBudget,
}
got, err := UpdateParams(in)
if err != nil {
t.Fatalf("UpdateParam error %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("GOT\n%v\nWANTED\n%v", got, want)
}
}

func TestUpdateParamsFromExisting(t *testing.T) {
defaultBeansPerUnit := DefaultBeansPerUnit()
customBeansPerUnit := NewStringBeans("foo", sdk.NewUint(1))
customPowerFlagFee := NewPowerFlagFee("bar", sdk.NewCoins(sdk.NewInt64Coin("baz", 2)))
customQueueSize := NewQueueSize("qux", int32(3))
customVatCleanup := UintMapEntry{"corge", sdk.NewUint(4)}
in := Params{
BeansPerUnit: append([]StringBeans{customBeansPerUnit}, defaultBeansPerUnit[2:4]...),
BootstrapVatConfig: "",
FeeUnitPrice: sdk.NewCoins(sdk.NewInt64Coin("denom", 789)),
PowerFlagFees: []PowerFlagFee{customPowerFlagFee},
QueueMax: []QueueSize{NewQueueSize(QueueInbound, int32(10)), customQueueSize},
VatCleanupBudget: []UintMapEntry{customVatCleanup, UintMapEntry{VatCleanupDefault, sdk.NewUint(10)}},
}
want := Params{
BeansPerUnit: append(append(in.BeansPerUnit, defaultBeansPerUnit[0:2]...), defaultBeansPerUnit[4:]...),
BootstrapVatConfig: in.BootstrapVatConfig,
FeeUnitPrice: in.FeeUnitPrice,
PowerFlagFees: append(in.PowerFlagFees, DefaultPowerFlagFees...),
QueueMax: in.QueueMax,
VatCleanupBudget: append(in.VatCleanupBudget, DefaultVatCleanupBudget[1:]...),
}
got, err := UpdateParams(in)
if err != nil {
t.Fatalf("UpdateParam error %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
t.Errorf("GOT\n%v\nWANTED\n%v", got, want)
}
}

0 comments on commit b8b18cc

Please sign in to comment.