Skip to content

Commit

Permalink
feat(tally): filter gas metering
Browse files Browse the repository at this point in the history
  • Loading branch information
hacheigriega committed Dec 18, 2024
1 parent 035b083 commit 03cb3c4
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 39 deletions.
10 changes: 9 additions & 1 deletion proto/sedachain/tally/v1/tally.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ option go_package = "github.com/sedaprotocol/seda-chain/x/tally/types";

// Params defines the parameters for the tally module.
message Params {
// max_tally_gas_limit is the maximum gas limit for a tally request.
// MaxTallyGasLimit is the maximum gas limit for a tally request.
uint64 max_tally_gas_limit = 1;
// FilterGasCostNone is the gas cost for a filter type none.
uint64 filter_gas_cost_none = 2;
// FilterGasCostMultiplierMode is the gas cost multiplier for a filter type
// mode.
uint64 filter_gas_cost_multiplier_mode = 3;
// FilterGasCostMultiplierStdDev is the gas cost multiplier for a filter type
// stddev.
uint64 filter_gas_cost_multiplier_stddev = 4;
}
11 changes: 6 additions & 5 deletions x/tally/keeper/endblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ func (k Keeper) FilterAndTally(ctx sdk.Context, req types.Request) (TallyResult,
}
paybackAddrHex := hex.EncodeToString(decodedBytes)

var outliers []int
outliers, result.consensus, result.proxyPubKeys, err = ApplyFilter(filter, reveals)
filterResult, err := k.ApplyFilter(ctx, filter, reveals, req.ReplicationFactor)
result.consensus = filterResult.Consensus
result.proxyPubKeys = filterResult.ProxyPubKeys
if err != nil {
return result, k.logErrAndRet(ctx, err, types.ErrApplyingFilter, req)
}
Expand All @@ -238,7 +239,7 @@ func (k Keeper) FilterAndTally(ctx sdk.Context, req types.Request) (TallyResult,
return result, k.logErrAndRet(ctx, err, types.ErrDecodingTallyInputs, req)
}

args, err := tallyVMArg(tallyInputs, reveals, outliers)
args, err := tallyVMArg(tallyInputs, reveals, filterResult.Outliers)
if err != nil {
return result, k.logErrAndRet(ctx, err, types.ErrConstructingTallyVMArgs, req)
}
Expand All @@ -247,7 +248,7 @@ func (k Keeper) FilterAndTally(ctx sdk.Context, req types.Request) (TallyResult,
if err != nil {
return result, k.logErrAndRet(ctx, err, types.ErrGettingMaxTallyGasLimit, req)
}
gasLimit := min(req.TallyGasLimit, maxGasLimit)
gasLimit := min(req.TallyGasLimit, maxGasLimit) - filterResult.GasUsed

k.Logger(ctx).Info(
"executing tally VM",
Expand Down Expand Up @@ -277,7 +278,7 @@ func (k Keeper) FilterAndTally(ctx sdk.Context, req types.Request) (TallyResult,
result.stderr = vmRes.Stderr
result.result = vmRes.Result
result.exitInfo = vmRes.ExitInfo
result.tallyGasUsed = vmRes.GasUsed
result.tallyGasUsed = vmRes.GasUsed + filterResult.GasUsed

return result, nil
}
Expand Down
42 changes: 32 additions & 10 deletions x/tally/keeper/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sedaprotocol/seda-chain/x/tally/types"
)

Expand All @@ -13,15 +14,25 @@ const (
filterTypeStdDev byte = 0x02
)

type FilterResult struct {
Outliers []int // outlier list
Consensus bool // whether consensus was reached
ProxyPubKeys []string // consensus data proxy public keys
GasUsed uint64 // gas used for filter
}

// ApplyFilter processes filter of the type specified in the first
// byte of consensus filter. It returns an outlier list, which is
// a boolean list where true at index i means that the reveal at
// index i is an outlier, consensus boolean, consensus data proxy
// public keys, and error. It assumes that the reveals and their
// proxy public keys are sorted.
func ApplyFilter(input []byte, reveals []types.RevealBody) ([]int, bool, []string, error) {
func (k Keeper) ApplyFilter(ctx sdk.Context, input []byte, reveals []types.RevealBody, replicationFactor int64) (FilterResult, error) {
var result FilterResult
result.Outliers = make([]int, len(reveals))

if len(input) == 0 {
return make([]int, len(reveals)), false, nil, types.ErrInvalidFilterType
return result, types.ErrInvalidFilterType
}

// Determine basic consensus on tuple of (exit_code, proxy_pub_keys)
Expand All @@ -39,34 +50,45 @@ func ApplyFilter(input []byte, reveals []types.RevealBody) ([]int, bool, []strin
}
}
if maxFreq*3 < len(reveals)*2 {
return make([]int, len(reveals)), false, nil, types.ErrNoBasicConsensus
return result, types.ErrNoBasicConsensus
}
result.ProxyPubKeys = proxyPubKeys

params, err := k.GetParams(ctx)
if err != nil {
return result, err
}

var filter types.Filter
var err error
switch input[0] {
case filterTypeNone:
filter, err = types.NewFilterNone(input)
result.GasUsed = params.FilterGasCostNone
case filterTypeMode:
filter, err = types.NewFilterMode(input)
result.GasUsed = params.FilterGasCostMultiplierMode * uint64(replicationFactor)
case filterTypeStdDev:
filter, err = types.NewFilterStdDev(input)
result.GasUsed = params.FilterGasCostMultiplierStddev * uint64(replicationFactor)
default:
return make([]int, len(reveals)), false, proxyPubKeys, types.ErrInvalidFilterType
return result, types.ErrInvalidFilterType
}
if err != nil {
return make([]int, len(reveals)), false, proxyPubKeys, err
return result, err
}

outliers, err := filter.ApplyFilter(reveals)
switch {
case err == nil:
return outliers, true, proxyPubKeys, nil
result.Outliers = outliers
result.Consensus = true
return result, nil
case errors.Is(err, types.ErrNoConsensus):
return outliers, false, proxyPubKeys, nil
result.Outliers = outliers
return result, nil
case errors.Is(err, types.ErrCorruptReveals):
return make([]int, len(reveals)), false, proxyPubKeys, err
return result, err
default:
return make([]int, len(reveals)), false, proxyPubKeys, err
return result, err
}
}
10 changes: 7 additions & 3 deletions x/tally/keeper/filter_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import (

"github.com/stretchr/testify/require"

"github.com/sedaprotocol/seda-chain/x/tally/keeper"
"github.com/sedaprotocol/seda-chain/x/tally/types"
)

func FuzzStdDevFilter(f *testing.F) {
fixture := initFixture(f)

err := fixture.tallyKeeper.SetParams(fixture.Context(), types.DefaultParams())
require.NoError(f, err)

f.Fuzz(func(t *testing.T, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 int64) {
source := rand.NewSource(time.Now().UnixNano())
t.Log("random testing with seed", source.Int63())
Expand Down Expand Up @@ -57,8 +61,8 @@ func FuzzStdDevFilter(f *testing.F) {
filter, err := hex.DecodeString(filterHex)
require.NoError(t, err)

outliers, _, _, err := keeper.ApplyFilter(filter, reveals)
require.Equal(t, expOutliers, outliers)
result, err := fixture.tallyKeeper.ApplyFilter(fixture.Context(), filter, reveals, int64(len(reveals)))
require.Equal(t, expOutliers, result.Outliers)
require.ErrorIs(t, err, nil)
})
}
Loading

0 comments on commit 03cb3c4

Please sign in to comment.