Skip to content

Commit

Permalink
fix review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
forcodedancing committed Jun 10, 2023
1 parent 5c08b16 commit 6c698f4
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 106 deletions.
206 changes: 206 additions & 0 deletions e2e/tests/payment_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
package tests

import (
"bytes"
"context"
"fmt"
"math"
"strconv"
"testing"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
"github.com/stretchr/testify/suite"

"github.com/bnb-chain/greenfield/e2e/core"
"github.com/bnb-chain/greenfield/sdk/keys"
"github.com/bnb-chain/greenfield/sdk/types"
storagetestutil "github.com/bnb-chain/greenfield/testutil/storage"
paymenttypes "github.com/bnb-chain/greenfield/x/payment/types"
storagetypes "github.com/bnb-chain/greenfield/x/storage/types"
)

type PaymentTestSuite struct {
Expand Down Expand Up @@ -59,6 +72,199 @@ func (s *PaymentTestSuite) TestPaymentAccount() {
s.Require().Equal(false, paymentAccount.PaymentAccount.Refundable)
}

func (s *PaymentTestSuite) updateParams(params paymenttypes.Params) {
var err error
validator := s.Validator.GetAddr()

ctx := context.Background()

msgUpdateParams := &paymenttypes.MsgUpdateParams{
Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
Params: params,
}

msgProposal, err := govtypesv1.NewMsgSubmitProposal(
[]sdk.Msg{msgUpdateParams},
sdk.Coins{sdk.NewCoin(s.BaseSuite.Config.Denom, types.NewIntFromInt64WithDecimal(100, types.DecimalBNB))},
validator.String(),
"test", "test", "test",
)
s.Require().NoError(err)

txRes := s.SendTxBlock(s.Validator, msgProposal)
s.Require().Equal(txRes.Code, uint32(0))

// 3. query proposal and get proposal ID
var proposalId uint64
for _, event := range txRes.Logs[0].Events {
if event.Type == "submit_proposal" {
for _, attr := range event.Attributes {
if attr.Key == "proposal_id" {
proposalId, err = strconv.ParseUint(attr.Value, 10, 0)
s.Require().NoError(err)
break
}
}
break
}
}
s.Require().True(proposalId != 0)

queryProposal := &govtypesv1.QueryProposalRequest{ProposalId: proposalId}
_, err = s.Client.GovQueryClientV1.Proposal(ctx, queryProposal)
s.Require().NoError(err)

// 4. submit MsgVote and wait the proposal exec
msgVote := govtypesv1.NewMsgVote(validator, proposalId, govtypesv1.OptionYes, "test")
txRes = s.SendTxBlock(s.Validator, msgVote)
s.Require().Equal(txRes.Code, uint32(0))

queryVoteParamsReq := govtypesv1.QueryParamsRequest{ParamsType: "voting"}
queryVoteParamsResp, err := s.Client.GovQueryClientV1.Params(ctx, &queryVoteParamsReq)
s.Require().NoError(err)

// 5. wait a voting period and confirm that the proposal success.
s.T().Logf("voting period %s", *queryVoteParamsResp.Params.VotingPeriod)
time.Sleep(*queryVoteParamsResp.Params.VotingPeriod)
proposalRes, err := s.Client.GovQueryClientV1.Proposal(ctx, queryProposal)
s.Require().NoError(err)
s.Require().Equal(proposalRes.Proposal.Status, govtypesv1.ProposalStatus_PROPOSAL_STATUS_PASSED)
}

func (s *PaymentTestSuite) createObject() (keys.KeyManager, string, string, storagetypes.Uint, []byte) {
var err error
sp := s.StorageProviders[0]
// CreateBucket
user := s.GenAndChargeAccounts(1, 1000000)[0]
bucketName := "ch" + storagetestutil.GenRandomBucketName()
msgCreateBucket := storagetypes.NewMsgCreateBucket(
user.GetAddr(), bucketName, storagetypes.VISIBILITY_TYPE_PRIVATE, sp.OperatorKey.GetAddr(),
nil, math.MaxUint, nil, 10000)
msgCreateBucket.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateBucket.GetApprovalBytes())
s.Require().NoError(err)
s.SendTxBlock(user, msgCreateBucket)

// CreateObject
objectName := storagetestutil.GenRandomObjectName()
// create test buffer
var buffer bytes.Buffer
line := `1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,1234567890,
1234567890,1234567890,1234567890,123`
// Create 1MiB content where each line contains 1024 characters.
for i := 0; i < 1024; i++ {
buffer.WriteString(fmt.Sprintf("[%05d] %s\n", i, line))
}
payloadSize := buffer.Len()
checksum := sdk.Keccak256(buffer.Bytes())
expectChecksum := [][]byte{checksum, checksum, checksum, checksum, checksum, checksum, checksum}
contextType := "text/event-stream"
msgCreateObject := storagetypes.NewMsgCreateObject(user.GetAddr(), bucketName, objectName, uint64(payloadSize), storagetypes.VISIBILITY_TYPE_PRIVATE, expectChecksum, contextType, storagetypes.REDUNDANCY_EC_TYPE, math.MaxUint, nil, nil)
msgCreateObject.PrimarySpApproval.Sig, err = sp.ApprovalKey.Sign(msgCreateObject.GetApprovalBytes())
s.Require().NoError(err)
s.SendTxBlock(user, msgCreateObject)

// HeadObject
queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{
BucketName: bucketName,
ObjectName: objectName,
}
queryHeadObjectResponse, err := s.Client.HeadObject(context.Background(), &queryHeadObjectRequest)
s.Require().NoError(err)
s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectName, objectName)
s.Require().Equal(queryHeadObjectResponse.ObjectInfo.BucketName, bucketName)

return user, bucketName, objectName, queryHeadObjectResponse.ObjectInfo.Id, checksum
}

func (s *PaymentTestSuite) sealObject(bucketName, objectName string, objectId storagetypes.Uint, checksum []byte) {
sp := s.StorageProviders[0]

secondarySPs := []sdk.AccAddress{
sp.OperatorKey.GetAddr(), sp.OperatorKey.GetAddr(),
sp.OperatorKey.GetAddr(), sp.OperatorKey.GetAddr(),
sp.OperatorKey.GetAddr(), sp.OperatorKey.GetAddr(),
}
msgSealObject := storagetypes.NewMsgSealObject(sp.SealKey.GetAddr(), bucketName, objectName, secondarySPs, nil)
sr := storagetypes.NewSecondarySpSignDoc(sp.OperatorKey.GetAddr(), objectId, checksum)
secondarySig, err := sp.ApprovalKey.Sign(sr.GetSignBytes())
s.Require().NoError(err)
err = storagetypes.VerifySignature(sp.ApprovalKey.GetAddr(), sdk.Keccak256(sr.GetSignBytes()), secondarySig)
s.Require().NoError(err)

secondarySigs := [][]byte{secondarySig, secondarySig, secondarySig, secondarySig, secondarySig, secondarySig}
msgSealObject.SecondarySpSignatures = secondarySigs
s.SendTxBlock(sp.SealKey, msgSealObject)

queryHeadObjectRequest := storagetypes.QueryHeadObjectRequest{
BucketName: bucketName,
ObjectName: objectName,
}
queryHeadObjectResponse, err := s.Client.HeadObject(context.Background(), &queryHeadObjectRequest)
s.Require().NoError(err)
s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectName, objectName)
s.Require().Equal(queryHeadObjectResponse.ObjectInfo.BucketName, bucketName)
s.Require().Equal(queryHeadObjectResponse.ObjectInfo.ObjectStatus, storagetypes.OBJECT_STATUS_SEALED)
}

func (s *PaymentTestSuite) TestVersionedParams() {
ctx := context.Background()
queryParamsRequest := paymenttypes.QueryParamsRequest{}
queryParamsResponse, err := s.Client.PaymentQueryClient.Params(ctx, &queryParamsRequest)
s.Require().NoError(err)

queryStreamRequest := paymenttypes.QueryGetStreamRecordRequest{Account: paymenttypes.ValidatorTaxPoolAddress.String()}
queryStreamResponse, err := s.Client.PaymentQueryClient.StreamRecord(ctx, &queryStreamRequest)
s.Require().NoError(err)
validatorTaxPoolRate := queryStreamResponse.StreamRecord.NetflowRate
s.T().Logf("netflow, validatorTaxPoolRate: %s", validatorTaxPoolRate)

// create bucket, create object
user, bucketName, objectName, objectId, checksum := s.createObject()

// update params
params := queryParamsResponse.GetParams()
oldReserveTime := params.VersionedParams.ReserveTime
oldValidatorTaxRate := params.VersionedParams.ValidatorTaxRate
s.T().Logf("params, ReserveTime: %d, ValidatorTaxRate: %s", oldReserveTime, oldValidatorTaxRate)

params.VersionedParams.ReserveTime = oldReserveTime * 2
params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate.MulInt64(2)

s.updateParams(params)
queryParamsResponse, err = s.Client.PaymentQueryClient.Params(ctx, &queryParamsRequest)
s.Require().NoError(err)
params = queryParamsResponse.GetParams()
s.T().Logf("params, ReserveTime: %d, ValidatorTaxRate: %s", params.VersionedParams.ReserveTime, params.VersionedParams.ValidatorTaxRate)

// seal object
s.sealObject(bucketName, objectName, objectId, checksum)

// delete object
msgDeleteObject := storagetypes.NewMsgDeleteObject(user.GetAddr(), bucketName, objectName)
s.SendTxBlock(user, msgDeleteObject)

// delete bucket
msgDeleteBucket := storagetypes.NewMsgDeleteBucket(user.GetAddr(), bucketName)
s.SendTxBlock(user, msgDeleteBucket)

queryStreamResponse, err = s.Client.PaymentQueryClient.StreamRecord(ctx, &queryStreamRequest)
s.Require().NoError(err)
s.Require().Equal(validatorTaxPoolRate, queryStreamResponse.StreamRecord.NetflowRate)

// revert params
params.VersionedParams.ReserveTime = oldReserveTime
params.VersionedParams.ValidatorTaxRate = oldValidatorTaxRate
s.updateParams(params)
}

func TestPaymentTestSuite(t *testing.T) {
suite.Run(t, new(PaymentTestSuite))
}
4 changes: 2 additions & 2 deletions e2e/tests/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ func (s *StorageTestSuite) TestPayment_Smoke() {
readPrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.ReadPrice
readChargeRate := readPrice.MulInt(sdk.NewIntFromUint64(queryHeadBucketResponse.BucketInfo.ChargedReadQuota)).TruncateInt()
s.T().Logf("readPrice: %s, readChargeRate: %s", readPrice, readChargeRate)
userTaxRate := paymentParams.Params.ValidatorTaxRate.MulInt(readChargeRate).TruncateInt()
userTaxRate := paymentParams.Params.VersionedParams.ValidatorTaxRate.MulInt(readChargeRate).TruncateInt()
userTotalRate := readChargeRate.Add(userTaxRate)
s.Require().Equal(usr.NetflowRate.Abs(), userTotalRate)
expectedOutFlows := []paymenttypes.OutFlow{
Expand Down Expand Up @@ -681,7 +681,7 @@ func (s *StorageTestSuite) TestPayment_AutoSettle() {
s.Require().NoError(err)
readPrice := queryGetSpStoragePriceByTimeResp.SpStoragePrice.ReadPrice
totalUserRate := readPrice.MulInt(sdkmath.NewIntFromUint64(bucketChargedReadQuota)).TruncateInt()
taxRateParam := paymentParams.Params.ValidatorTaxRate
taxRateParam := paymentParams.Params.VersionedParams.ValidatorTaxRate
taxStreamRate := taxRateParam.MulInt(totalUserRate).TruncateInt()
expectedRate := totalUserRate.Add(taxStreamRate)
paymentAccountBNBNeeded := expectedRate.Mul(sdkmath.NewIntFromUint64(reserveTime))
Expand Down
12 changes: 6 additions & 6 deletions proto/greenfield/payment/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ message Params {
uint64 max_auto_force_settle_num = 4 [(gogoproto.moretags) = "yaml:\"max_auto_force_settle_num\""];
// The denom of fee charged in payment module
string fee_denom = 5 [(gogoproto.moretags) = "yaml:\"fee_denom\""];
// The tax rate to pay for validators in storage payment. The default value is 1%(0.01)
string validator_tax_rate = 6 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

// VersionedParams defines the parameters with multiple versions, each version is stored with different timestamp.
message VersionedParams {
// Time duration which the buffer balance need to be reserved for NetOutFlow e.g. 6 month
uint64 reserve_time = 1 [(gogoproto.moretags) = "yaml:\"reserve_time\""];
// The tax rate to pay for validators in storage payment. The default value is 1%(0.01)
string validator_tax_rate = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
29 changes: 15 additions & 14 deletions x/payment/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ var (
KeyFeeDenom = []byte("FeeDenom")
KeyValidatorTaxRate = []byte("ValidatorTaxRate")

DefaultReserveTime uint64 = 180 * 24 * 60 * 60 // 180 days
DefaultForcedSettleTime uint64 = 24 * 60 * 60 // 1 day
DefaultPaymentAccountCountLimit uint64 = 200
DefaultMaxAutoForceSettleNum uint64 = 100
DefaultFeeDenom string = "BNB"
DefaultValidatorTaxRate sdk.Dec = sdk.NewDecWithPrec(1, 2) // 1%
DefaultReserveTime uint64 = 180 * 24 * 60 * 60 // 180 days
DefaultValidatorTaxRate sdk.Dec = sdk.NewDecWithPrec(1, 2) // 1%

DefaultForcedSettleTime uint64 = 24 * 60 * 60 // 1 day
DefaultPaymentAccountCountLimit uint64 = 200
DefaultMaxAutoForceSettleNum uint64 = 100
DefaultFeeDenom string = "BNB"
)

// ParamKeyTable the param key table for launch module
Expand All @@ -33,43 +34,42 @@ func ParamKeyTable() paramtypes.KeyTable {
// NewParams creates a new Params instance
func NewParams(
reserveTime uint64,
validatorTaxRate sdk.Dec,
forcedSettleTime uint64,
paymentAccountCountLimit uint64,
maxAutoForceSettleNum uint64,
feeDenom string,
validatorTaxRate sdk.Dec,
) Params {
return Params{
VersionedParams: VersionedParams{ReserveTime: reserveTime},
VersionedParams: VersionedParams{ReserveTime: reserveTime, ValidatorTaxRate: validatorTaxRate},
ForcedSettleTime: forcedSettleTime,
PaymentAccountCountLimit: paymentAccountCountLimit,
MaxAutoForceSettleNum: maxAutoForceSettleNum,
FeeDenom: feeDenom,
ValidatorTaxRate: validatorTaxRate,
}
}

// DefaultParams returns a default set of parameters
func DefaultParams() Params {
return NewParams(
DefaultReserveTime,
DefaultValidatorTaxRate,
DefaultForcedSettleTime,
DefaultPaymentAccountCountLimit,
DefaultMaxAutoForceSettleNum,
DefaultFeeDenom,
DefaultValidatorTaxRate,
)
}

// ParamSetPairs get the params.ParamSet
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(KeyReserveTime, &p.VersionedParams.ReserveTime, validateReserveTime),
paramtypes.NewParamSetPair(KeyValidatorTaxRate, &p.VersionedParams.ValidatorTaxRate, validateValidatorTaxRate),
paramtypes.NewParamSetPair(KeyForcedSettleTime, &p.ForcedSettleTime, validateForcedSettleTime),
paramtypes.NewParamSetPair(KeyPaymentAccountCountLimit, &p.PaymentAccountCountLimit, validatePaymentAccountCountLimit),
paramtypes.NewParamSetPair(KeyMaxAutoForceSettleNum, &p.MaxAutoForceSettleNum, validateMaxAutoForceSettleNum),
paramtypes.NewParamSetPair(KeyFeeDenom, &p.FeeDenom, validateFeeDenom),
paramtypes.NewParamSetPair(KeyValidatorTaxRate, &p.ValidatorTaxRate, validateValidatorTaxRate),
}
}

Expand All @@ -79,6 +79,10 @@ func (p Params) Validate() error {
return err
}

if err := validateValidatorTaxRate(p.VersionedParams.ValidatorTaxRate); err != nil {
return err
}

if err := validateForcedSettleTime(p.ForcedSettleTime); err != nil {
return err
}
Expand All @@ -95,9 +99,6 @@ func (p Params) Validate() error {
return err
}

if err := validateValidatorTaxRate(p.ValidatorTaxRate); err != nil {
return err
}
return nil
}

Expand Down
Loading

0 comments on commit 6c698f4

Please sign in to comment.