Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Value Renderers for number and coin #10038

Closed
wants to merge 38 commits into from

Conversation

cyberbono3
Copy link
Contributor

Part of TX working group.

Description

Closes: #9955


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • followed the guidelines for building modules
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed ! in the type prefix if API or client breaking change
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic
  • reviewed API design and naming
  • reviewed documentation is accurate
  • reviewed tests and test coverage
  • manually tested (if applicable)

@codecov
Copy link

codecov bot commented Aug 31, 2021

Codecov Report

Merging #10038 (28b5890) into master (94377f1) will increase coverage by 0.40%.
The diff coverage is 79.16%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #10038      +/-   ##
==========================================
+ Coverage   63.72%   64.13%   +0.40%     
==========================================
  Files         573      576       +3     
  Lines       53766    54751     +985     
==========================================
+ Hits        34263    35115     +852     
- Misses      17555    17659     +104     
- Partials     1948     1977      +29     
Impacted Files Coverage Δ
types/valuerenderer/valuerenderer.go 79.16% <79.16%> (ø)
x/mint/keeper/querier.go 2.85% <0.00%> (-71.43%) ⬇️
x/params/keeper/grpc_query.go 73.68% <0.00%> (-10.53%) ⬇️
x/bank/types/params.go 95.00% <0.00%> (-1.00%) ⬇️
store/gaskv/store.go 100.00% <0.00%> (ø)
x/bank/migrations/v045/keys.go 100.00% <0.00%> (ø)
x/bank/migrations/v045/store.go 75.00% <0.00%> (ø)
types/module/module.go 70.27% <0.00%> (+0.32%) ⬆️
x/gov/keeper/msg_server.go 2.11% <0.00%> (+0.45%) ⬆️
client/flags/flags.go 21.81% <0.00%> (+0.76%) ⬆️
... and 12 more

@orijbot
Copy link

orijbot commented Sep 1, 2021

@cyberbono3
Copy link
Contributor Author

I suggest the next implementation plan.

  1. Add WithDefaultValueRenderer method on client.Context in context.go which sets DefaultValueRenderer on clientCtx field
  2. Add WithDefaultValueRenderer method into InitClientCtx
  3. Inside types/valuerenderer add cmd.go file with CLI root command valuerenderer and 2 subcommands:
  • format 2 args: amount and srcDenom runs func (dvr DefaultValueRenderer) Format(x interface{}) (string, error) { under the hood to address sdk.Coin as x agrument;
  • parse 1 arg: s string runs func (dvr DefaultValueRenderer) Parse(s string) (interface{}, error) { under the good;
  1. This format CLI command will use client.Context from cmd clientCtx, err := client.GetClientQueryContext(cmd)
  2. Instantiate queryHelper and call queryClient.DenomsMetadata
queryHelper := baseapp.NewQueryServerTestHelper(clientCtx, clientCtx.InterfaceRegistry())
queryClient := types.NewQueryClient(queryHelper)
req := &types.QueryDenomsMetadataRequest{
			Pagination: &query.PageRequest{
				Limit:      3,
				CountTotal: true,
			},
}
res, err := queryClient.DenomsMetadata(clientCtx, req)
  1. Then get metadata from res and perform amount conversion from srcDenom to metadata.Display in Format method

Does it sound good to you, @clevinson ?

@clevinson
Copy link
Contributor

I'm not sure I understand why we need a CLI method for value renderers. Was that discussed in one of the meetings? I can't seem to see any mention of it in the issue #9955, and don't really understand the use case.

From my understanding, all we need to implement in this PR would a DefaultValueRenderer type that implements the ValueRenderer interface described in #9955.

Looking at the existing code a few other thoughts-

If want to pass in to DefaultValueRenderer only a denom metadata querier function, I think we should expect something with function signature provided by the grpc query service. However, since "context" won't necessarily be available within the DefaultValueRenderer, it might be better to pass in the bankkeeper, and query using bk.DenomMetadata() when we need to look up the display denom for a given base denom.

@lgtm-com
Copy link

lgtm-com bot commented Sep 8, 2021

This pull request introduces 1 alert when merging 24ae2f4 into 37dbfec - view on LGTM.com

new alerts:

  • 1 for Useless assignment to field

@lgtm-com
Copy link

lgtm-com bot commented Sep 8, 2021

This pull request introduces 1 alert when merging b1d15ff into 37dbfec - view on LGTM.com

new alerts:

  • 1 for Useless assignment to field

Parse(context.Context, string) (interface{}, error)
}

// denomQuerierFunc takes a context and a denom as arguments and returns metadata, error
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's update a comment to something more meaningful. We know the types, instead, describe what the function should do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope it sounds better: denomQuerierFunc should take context and baseDenom to invoke DenomMetaData method on queryClient. This method will returnbanktypes.Metadata.

type denomQuerierFunc func(context.Context, string) (banktypes.Metadata, error)

// DefaultValueRenderer defines a struct that implements ValueRenderer interface
type DefaultValueRenderer struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to repeat the package name in the struct name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does DefaultRenderer instead of DefaultValueRenderer sound better to you?

types/valuerenderer/valuerenderer.go Outdated Show resolved Hide resolved
types/valuerenderer/valuerenderer.go Outdated Show resolved Hide resolved
return sb.String(), nil
}

// TODO address the cass where denom starts with "u"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this TODO still relevant?

Copy link
Contributor Author

@cyberbono3 cyberbono3 Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, there is a case, where denom might start with "u", e.g. urobert. In this case this is problematic to convert urobert to baseDenom by invoking convertToBaseDenom(denom string) string, cause baseDenom always start with "u".

types/valuerenderer/valuerenderer.go Outdated Show resolved Hide resolved
types/valuerenderer/valuerenderer.go Outdated Show resolved Hide resolved
return denom
// e.g. mregen => uregen
case strings.HasPrefix(denom, "m"):
return "u" + denom[1:]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m stands for mili. Why are you overwriting this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to convert it to banktypes.Metadata.Base which represents the minimum denom and always starts with "u" if I am not mistaken.

}
// remove all commas
str := strings.ReplaceAll(s, ",", "")
re := regexp.MustCompile(`(\d+)(\w+)`)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should compile the regexp once, and store it as a module private variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather make it global since valuerenderer_test package imports that.

types/valuerenderer/valuerenderer.go Outdated Show resolved Hide resolved
}

// Parse parses a string and takes a decision whether to convert it into Coin or Uint
func (dvr DefaultValueRenderer) Parse(ctx context.Context, s string) (interface{}, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returning an empty interface is a bad idea. Why do we need a single function to work both with numbers and coins?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ValueRenderer interface has been designed by @aaronc

type ValueRenderer interface {
  Format(ctx context.Context, interface{}) (string, error)
  Parse(ctx context.Context, s string) (interface{}, error)
}

Can we split Parse into 2 functions ?

ParseCoin(ctx context.Context, s string) (types.Coin, error)
ParseUint(ctx context.Context, s string) (types.Uint, error)

cc @aaronc @AmauryM

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that would be a better idea.

@@ -14,6 +14,8 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

var RegExp = regexp.MustCompile(`(\d+)(\w+)`)
Copy link
Contributor Author

@cyberbono3 cyberbono3 Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made RegExp global variable since valuerenderer_test package imports that. Does it sound good ?


// TODO address the cass where denom starts with "u"
// baseFromDenom converts denom to banktypes.Metadata.Base that is used in banktypes.QueryDenomMetadataRequest. queryClient.DenomMetadata method takes Banktypes.QueryDenomMetadataRequest and context as arguments and returns resp.Metadata.
func baseFromDenom(denom string) (string, error) {
Copy link
Contributor Author

@cyberbono3 cyberbono3 Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

baseFromDenom converts denom to banktypes.Metadata.Base that is used in banktypes.QueryDenomMetadataRequest here. queryClient.DenomMetadata method takes banktypes.QueryDenomMetadataRequest and context as arguments and returns resp.Metadata.


// TODO address the cass where denom starts with "u"
// baseFromDenom converts denom to banktypes.Metadata.Base that is used in banktypes.QueryDenomMetadataRequest. queryClient.DenomMetadata method takes Banktypes.QueryDenomMetadataRequest and context as arguments and returns resp.Metadata.
func baseFromDenom(denom string) (string, error) {
Copy link
Contributor Author

@cyberbono3 cyberbono3 Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does name baseFromDenom sound good to you , @robert-zaremba ?

// TODO address the cass where denom starts with "u"
// baseFromDenom converts denom to banktypes.Metadata.Base that is used in banktypes.QueryDenomMetadataRequest. queryClient.DenomMetadata method takes Banktypes.QueryDenomMetadataRequest and context as arguments and returns resp.Metadata.
func baseFromDenom(denom string) (string, error) {
if len(denom) == 0 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If len(denom) == 0 I yield an error

@amaury1093
Copy link
Contributor

Closing, and let's re-prioritize this work wrt #10251.

@amaury1093 amaury1093 closed this Sep 28, 2021
@amaury1093 amaury1093 deleted the cyberbono3/value-renderer branch September 28, 2021 15:58
@robert-zaremba
Copy link
Collaborator

@AmauryM - the value render will still be needed for the sign mode textual, so maybe we should still keep the PR open and update once there will be more requirements?

@amaury1093 amaury1093 restored the cyberbono3/value-renderer branch September 29, 2021 14:42
@amaury1093
Copy link
Contributor

amaury1093 commented Sep 29, 2021

Sure, but i'll put as draft.

@amaury1093 amaury1093 reopened this Sep 29, 2021
@amaury1093 amaury1093 marked this pull request as draft September 29, 2021 14:42
@github-actions
Copy link
Contributor

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale label Nov 14, 2021
@tac0turtle
Copy link
Member

@AmauryM can this be worked on or is it blocked?

@amaury1093
Copy link
Contributor

It's blocked, happy to close this.

@amaury1093 amaury1093 closed this Nov 15, 2021
@alexanderbez alexanderbez deleted the cyberbono3/value-renderer branch April 22, 2022 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Value Renderers for number and coin
7 participants