Skip to content

Commit

Permalink
Merge pull request #3265 from oasisprotocol/tjanez/csr-enum-lists
Browse files Browse the repository at this point in the history
Pretty print commission schedule rates and rate bounds as enumerated lists
  • Loading branch information
tjanez authored Sep 14, 2020
2 parents 5a760da + 7284f83 commit 62ce4c6
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 13 deletions.
1 change: 1 addition & 0 deletions .changelog/3265.feature.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/staking/api: Add `PrettyPrintCommissionScheduleIndexInfixes()` helper
5 changes: 5 additions & 0 deletions .changelog/3265.feature.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
go/staking/api: Update commission schedule rate and rate bound pretty prints

Pretty print rates and rate bounds as enumerated lists to enable easier
inspection of commission schedule (amendments) in combination with a
hardware-based signer plugin.
3 changes: 3 additions & 0 deletions go/common/prettyprint/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ var (
// ContextKeyTokenValueExponent is the key to retrieve the token's value
// base-10 exponent from a context.
ContextKeyTokenValueExponent = contextKey("staking/token-value-exponent")
// ContextKeyCommissionScheduleIndex is the key to retrieve the rate (bound)
// index in a commission schedule (amendment).
ContextKeyCommissionScheduleIndex = contextKey("staking/commission-schedule-index")
)

type contextKey string
18 changes: 12 additions & 6 deletions go/oasis-test-runner/scenario/e2e/stake_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,8 @@ func (sc *stakeCLIImpl) checkGeneralAccount(

var b bytes.Buffer
expectedAccount.PrettyPrint(ctx, " ", &b)
match := regexp.MustCompile(b.String()).FindStringSubmatch(accountInfo)
regexPattern := regexp.QuoteMeta(b.String())
match := regexp.MustCompile(regexPattern).FindStringSubmatch(accountInfo)
if match == nil {
return fmt.Errorf(
"checkGeneralAccount: couldn't find expected general account %+v in account info", expectedAccount,
Expand All @@ -649,7 +650,8 @@ func (sc *stakeCLIImpl) checkEscrowAccountSharePool(
var b bytes.Buffer
fmt.Fprintf(&b, "%s%s:\n", prefix, sharePoolName)
expectedSharePool.PrettyPrint(ctx, prefix+" ", &b)
match := regexp.MustCompile(b.String()).FindStringSubmatch(accountInfo)
regexPattern := regexp.QuoteMeta(b.String())
match := regexp.MustCompile(regexPattern).FindStringSubmatch(accountInfo)
if match == nil {
return fmt.Errorf(
"checkEscrowAccountSharePool: couldn't find expected escrow %s share pool %+v in account info",
Expand All @@ -671,10 +673,12 @@ func (sc *stakeCLIImpl) checkCommissionScheduleRates(
return err
}

for _, expectedRate := range expectedRates {
for i, expectedRate := range expectedRates {
var b bytes.Buffer
ctx = context.WithValue(ctx, prettyprint.ContextKeyCommissionScheduleIndex, i)
expectedRate.PrettyPrint(ctx, " ", &b)
match := regexp.MustCompile(b.String()).FindStringSubmatch(accountInfo)
regexPattern := regexp.QuoteMeta(b.String())
match := regexp.MustCompile(regexPattern).FindStringSubmatch(accountInfo)
if match == nil {
return fmt.Errorf(
"checkCommissionScheduleRates: couldn't find an expected commission schedule rate %+v in account info",
Expand All @@ -697,10 +701,12 @@ func (sc *stakeCLIImpl) checkCommissionScheduleRateBounds(
return err
}

for _, expectedBound := range expectedRateBounds {
for i, expectedBound := range expectedRateBounds {
var b bytes.Buffer
ctx = context.WithValue(ctx, prettyprint.ContextKeyCommissionScheduleIndex, i)
expectedBound.PrettyPrint(ctx, " ", &b)
match := regexp.MustCompile(b.String()).FindStringSubmatch(accountInfo)
regexPattern := regexp.QuoteMeta(b.String())
match := regexp.MustCompile(regexPattern).FindStringSubmatch(accountInfo)
if match == nil {
return fmt.Errorf(
"checkCommissionScheduleRateBounds: couldn't find an expected commission schedule rate bound %+v in account info",
Expand Down
18 changes: 11 additions & 7 deletions go/staking/api/commission.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ type CommissionRateStep struct {
// PrettyPrint writes a pretty-printed representation of CommissionRateStep to
// the given writer.
func (crs CommissionRateStep) PrettyPrint(ctx context.Context, prefix string, w io.Writer) {
fmt.Fprintf(w, "%s- Start: epoch %d\n", prefix, crs.Start)
indexInfix, emptyInfix := PrettyPrintCommissionScheduleIndexInfixes(ctx)

fmt.Fprintf(w, "%s Rate: %s\n", prefix, PrettyPrintCommissionRatePercentage(crs.Rate))
fmt.Fprintf(w, "%s%sstart: epoch %d\n", prefix, indexInfix, crs.Start)
fmt.Fprintf(w, "%s%srate: %s\n", prefix, emptyInfix, PrettyPrintCommissionRatePercentage(crs.Rate))
}

// PrettyType returns a representation of CommissionRateStep that can be used
Expand All @@ -77,10 +78,11 @@ type CommissionRateBoundStep struct {
// PrettyPrint writes a pretty-printed representation of CommissionRateBoundStep
// to the given writer.
func (crbs CommissionRateBoundStep) PrettyPrint(ctx context.Context, prefix string, w io.Writer) {
fmt.Fprintf(w, "%s- Start: epoch %d\n", prefix, crbs.Start)
indexInfix, emptyInfix := PrettyPrintCommissionScheduleIndexInfixes(ctx)

fmt.Fprintf(w, "%s Minimum Rate: %s\n", prefix, PrettyPrintCommissionRatePercentage(crbs.RateMin))
fmt.Fprintf(w, "%s Maximum Rate: %s\n", prefix, PrettyPrintCommissionRatePercentage(crbs.RateMax))
fmt.Fprintf(w, "%s%sstart: epoch %d\n", prefix, indexInfix, crbs.Start)
fmt.Fprintf(w, "%s%sminimum rate: %s\n", prefix, emptyInfix, PrettyPrintCommissionRatePercentage(crbs.RateMin))
fmt.Fprintf(w, "%s%smaximum rate: %s\n", prefix, emptyInfix, PrettyPrintCommissionRatePercentage(crbs.RateMax))
}

// PrettyType returns a representation of CommissionRateBoundStep that can be
Expand All @@ -105,7 +107,8 @@ func (cs CommissionSchedule) PrettyPrint(ctx context.Context, prefix string, w i
fmt.Fprintf(w, "%sRates: (none)\n", prefix)
} else {
fmt.Fprintf(w, "%sRates:\n", prefix)
for _, rate := range cs.Rates {
for i, rate := range cs.Rates {
ctx = context.WithValue(ctx, prettyprint.ContextKeyCommissionScheduleIndex, i)
rate.PrettyPrint(ctx, prefix+" ", w)
}
}
Expand All @@ -114,7 +117,8 @@ func (cs CommissionSchedule) PrettyPrint(ctx context.Context, prefix string, w i
fmt.Fprintf(w, "%sRate Bounds: (none)\n", prefix)
} else {
fmt.Fprintf(w, "%sRate Bounds:\n", prefix)
for _, rateBound := range cs.Bounds {
for i, rateBound := range cs.Bounds {
ctx = context.WithValue(ctx, prettyprint.ContextKeyCommissionScheduleIndex, i)
rateBound.PrettyPrint(ctx, prefix+" ", w)
}
}
Expand Down
88 changes: 88 additions & 0 deletions go/staking/api/commission_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package api

import (
"bytes"
"context"
"testing"

"github.com/stretchr/testify/require"

"github.com/oasisprotocol/oasis-core/go/common/prettyprint"
"github.com/oasisprotocol/oasis-core/go/common/quantity"
epochtime "github.com/oasisprotocol/oasis-core/go/epochtime/api"
)
Expand Down Expand Up @@ -770,3 +773,88 @@ func TestCommissionSchedule(t *testing.T) {
require.Equal(t, epochtime.EpochTime(10), cs.Rates[0].Start, "prune 10 rates start")
require.Equal(t, epochtime.EpochTime(10), cs.Bounds[0].Start, "prune 10 bounds start")
}

func TestPrettyPrintCommissionRateStep(t *testing.T) {
require := require.New(t)

for _, t := range []struct {
expectedPPrint string
rateStart epochtime.EpochTime
rateNumerator *quantity.Quantity
index int
}{
{
"" +
"(1) start: epoch 10\n" +
" rate: 0.0%\n",
epochtime.EpochTime(10), quantity.NewFromUint64(0), 0,
},
{
"" +
"(11) start: epoch 20\n" +
" rate: 50.0%\n",
epochtime.EpochTime(20), quantity.NewFromUint64(50_000), 10,
},
{
"" +
"(101) start: epoch 100\n" +
" rate: 100.0%\n",
epochtime.EpochTime(100), quantity.NewFromUint64(100_000), 100,
},
} {
rateStep := CommissionRateStep{
Start: t.rateStart,
Rate: *t.rateNumerator,
}
var b bytes.Buffer
ctx := context.WithValue(context.Background(), prettyprint.ContextKeyCommissionScheduleIndex, t.index)
rateStep.PrettyPrint(ctx, "", &b)
pPrint := b.String()
require.Equal(t.expectedPPrint, pPrint, "obtained pretty print didn't match expected value")
}
}

func TestPrettyPrintCommissionRateBoundStep(t *testing.T) {
require := require.New(t)

for _, t := range []struct {
expectedPPrint string
rateStart epochtime.EpochTime
rateMinNumerator *quantity.Quantity
rateMaxNumerator *quantity.Quantity
index int
}{
{
"" +
"(1) start: epoch 10\n" +
" minimum rate: 0.0%\n" +
" maximum rate: 20.0%\n",
epochtime.EpochTime(10), quantity.NewFromUint64(0), quantity.NewFromUint64(20_000), 0,
},
{
"" +
"(11) start: epoch 20\n" +
" minimum rate: 40.0%\n" +
" maximum rate: 60.0%\n",
epochtime.EpochTime(20), quantity.NewFromUint64(40_000), quantity.NewFromUint64(60_000), 10,
},
{
"" +
"(101) start: epoch 100\n" +
" minimum rate: 0.0%\n" +
" maximum rate: 100.0%\n",
epochtime.EpochTime(100), quantity.NewFromUint64(0), quantity.NewFromUint64(100_000), 100,
},
} {
rateStep := CommissionRateBoundStep{
Start: t.rateStart,
RateMin: *t.rateMinNumerator,
RateMax: *t.rateMaxNumerator,
}
var b bytes.Buffer
ctx := context.WithValue(context.Background(), prettyprint.ContextKeyCommissionScheduleIndex, t.index)
rateStep.PrettyPrint(ctx, "", &b)
pPrint := b.String()
require.Equal(t.expectedPPrint, pPrint, "obtained pretty print didn't match expected value")
}
}
16 changes: 16 additions & 0 deletions go/staking/api/prettyprint.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package api

import (
"context"
"fmt"
"strings"

"github.com/oasisprotocol/oasis-core/go/common/prettyprint"
"github.com/oasisprotocol/oasis-core/go/common/quantity"
Expand All @@ -20,3 +22,17 @@ func PrettyPrintCommissionRatePercentage(rateNumerator quantity.Quantity) string
denominatorExp := commissionRateDenominatorExponent - 2
return fmt.Sprintf("%s%%", prettyprint.QuantityFrac(rateNumerator, denominatorExp))
}

// PrettyPrintCommissionScheduleIndexInfixes returns two infixes:
// - indexInfix holds the infix to use to pretty print the given commission
// schedule rate (bound) index
// - emptyInfix holds the infix to use to pretty print an empty string of an
// equivalent length
func PrettyPrintCommissionScheduleIndexInfixes(ctx context.Context) (indexInfix, emptyInfix string) {
index, ok := ctx.Value(prettyprint.ContextKeyCommissionScheduleIndex).(int)
if ok {
indexInfix = fmt.Sprintf("(%d) ", index+1)
emptyInfix = strings.Repeat(" ", len(indexInfix))
}
return
}
25 changes: 25 additions & 0 deletions go/staking/api/prettyprint_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package api

import (
"context"
"testing"

"github.com/stretchr/testify/require"

"github.com/oasisprotocol/oasis-core/go/common/prettyprint"
"github.com/oasisprotocol/oasis-core/go/common/quantity"
)

Expand All @@ -29,3 +31,26 @@ func TestPrettyPrintCommissionRatePercentage(t *testing.T) {
require.Equal(t.expectedRate, rate, "obtained pretty print didn't match expected value")
}
}

func TestPrettyPrintCommissionScheduleIndexInfixes(t *testing.T) {
require := require.New(t)

for _, t := range []struct {
expectedIndexInfix string
expectedEmptyInfix string
index int
indexPresent bool
}{
{"(1) ", " ", 0, true},
{"(2) ", " ", 1, true},
{"(10) ", " ", 9, true},
{"(123) ", " ", 122, true},
{"(2345678) ", " ", 2345677, true},
} {
require.Equal(len(t.expectedIndexInfix), len(t.expectedEmptyInfix), "expected index and empty infixes should be of equal length")
ctx := context.WithValue(context.Background(), prettyprint.ContextKeyCommissionScheduleIndex, t.index)
indexInfix, emptyInfix := PrettyPrintCommissionScheduleIndexInfixes(ctx)
require.Equal(t.expectedIndexInfix, indexInfix, "obtained index infix didn't match expected value")
require.Equal(t.expectedEmptyInfix, emptyInfix, "obtained empty infix didn't match expected value")
}
}

0 comments on commit 62ce4c6

Please sign in to comment.