-
Notifications
You must be signed in to change notification settings - Fork 111
swarm: repeated --ens-api CLI flag (#14386) #142
Conversation
Implement a CLI flag that can be repeated to allow multiple ENS resolvers for different TLDs.
Should this replace the |
Hi Lewis, since the flag --ens-endpoint can be repeated and can contain only the endpoint url/path, flags it can be simplified, that there is only one flag --ens-api which would function the same way as --ens-endpoint does now, just with the same default value, as the --ens-api does have now. One small problem is with --ens-addr, which can not be used with repeated --ens-api flag. I can "merge" --ens-endpoint functionality into --ens-api (default value) flag, and restrict --ens-addr to be allowed only if --ens-api is specified once. Would such change make sense? |
@janos so personally, I think the command line interface should be for "simple" use cases (e.g. I just want to point Swarm at mainnet / ropsten / rinkeby etc. to resolve all addresses), and we should promote using a config file for more complex use cases (@holisticode is currently working on improving the config file). A config file can be self documenting with comments and support structures like maps and arrays in a natural way, whereas command line flags are quite cumbersome and error prone. If we do expand the CLI args, I'd at least like to see only one way to configure ENS (either multiple |
Allow multiple --ens-api flags to be specified with value format [tld:][contract-addr@]url. Backward compatibility with only one --ens-api flag and --ens-addr flag is preserved and conflict cases are handled: - multiple --ens-api with --ens-addr returns an error - single --ens-api with contract address and --ens-addr with different contract address returns an error Previously implemented --ens-endpoint is removed. Its functionality is replaced with multiple --ens-api flags.
@lmars the latest change addresses the last part of you comment. Flag --ens-endpoint is removed and --ens-api can be repeated. |
cmd/swarm/main.go
Outdated
case 1: | ||
// Check if only one --ens-api is specified in order to use --ens-addr value | ||
// to preserve the backward compatibility with single --ens-api flag. | ||
// Multiple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is incomplete.
cmd/swarm/main.go
Outdated
Name: "ens-api", | ||
Usage: "URL of the Ethereum API provider to use for ENS record lookups", | ||
Value: node.DefaultIPCEndpoint("geth"), | ||
Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we should deprecate --ens-addr
then?
cmd/swarm/main.go
Outdated
// Check if only one --ens-api is specified in order to use --ens-addr value | ||
// to preserve the backward compatibility with single --ens-api flag. | ||
// Multiple | ||
c := parseFlagEnsAPI(ensAPIs[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We currently treat --ens-api ''
as an indication to disable the use of ENS so we should check for that case here (but to be honest, we should have an explicit flag like --no-ens
instead).
cmd/swarm/main.go
Outdated
} | ||
if err := stack.Register(boot); err != nil { | ||
utils.Fatalf("Failed to register the Swarm service: %v", err) | ||
} | ||
} | ||
|
||
func parseFlagEnsAPI(s string) swarm.ENSClientConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment to describe what this function is doing.
swarm/api/api.go
Outdated
func MultiResolverOptionWithResolver(r Resolver, tld string) MultiResolverOption { | ||
return func(m *MultiResolver) { | ||
if _, ok := m.resolvers[tld]; !ok { | ||
m.resolvers[tld] = []Resolver{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need for this assignment.
swarm/api/api.go
Outdated
// NewMultiResolver creates a new instance of MultiResolver. | ||
func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) { | ||
m = &MultiResolver{ | ||
resolvers: map[string][]Resolver{}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use make(map[string][]Resolver)
to initialise the map (that is the convention in the go-ethereum codebase).
swarm/api/api.go
Outdated
// the Hash from the the first one which does not return error | ||
// will be returned. | ||
func (m MultiResolver) Resolve(addr string) (h common.Hash, err error) { | ||
rs, _ := m.resolvers[""] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to assign _
here.
swarm/api/api.go
Outdated
func (m MultiResolver) Resolve(addr string) (h common.Hash, err error) { | ||
rs, _ := m.resolvers[""] | ||
if i := strings.LastIndex(addr, "."); i >= 0 { | ||
rstld, ok := m.resolvers[addr[i+1:]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be more readable using path.Ext
.
@holisticode could you review this pull request as it is related in some parts to this PR ethereum/go-ethereum#15548? |
Merge with changes that implement config file PR #15548. Field *EnsApi string* in swarm/api.Config is replaced with *EnsAPIs []string*. A new field *EnsDisabled bool* is added to swarm/api.Config for easy way to disable ENS resolving with config file. Signature of function swarm.NewSwarm is changed and simplified.
@holisticode this PR is updated with the changes that you did regarding config file feature. Could you review the changes? There is one new filed EnsDisabled in swarm/api.Config. If that is ok, would it make sense to have cli flag --ens-disabled (as @lmars already suggested) and env ver SWARM_ENS_DISABLED? One backward incompatible change is replacing Config field EnsApi string with EnsAPIs []string. Config file feature has been added recently, but if backward compatibility is needed, EnsApi field can be added and handled. |
Fix a conflict in cmd/swarm envVarsOverride function.
For the note: team decision is that we disable ENS by default |
Specifying ENS API CLI flag, env variable or configuration field is required for ENS resolving. Backward compatibility is preserved with --ens-api="" CLI flag value.
} | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a test for invalid format via command line or env var params? E.g. --ens-api ":<addr>"
or --ens-api "test-tld:"
? Can you think of other invalid ones? Are we also testing with multiple addresses per TLD? With no default resolver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Will add test cases for invalid formats.
Test cases for multiple resolvers are handled in swarm/api.TestMultiResolver with various combinations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validations for missing tld, contract address or url is added to cmd/swarm.validateConfg.
Name: "ens-api", | ||
Usage: "URL of the Ethereum API provider to use for ENS record lookups", | ||
Usage: "ENS API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried to see if it works when the option is provided via config file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the behavior if only addresses with TLDs are provided, do we end up without a default one? Is it even possible to identify the default one if no default has been provided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The toml configuration file is loading the values this way:
EnsAPIs = [
"endpoint1",
"test:endpoint2",
]
The ENS API endpoint configuration is implemented to be most explicit. If no default endpoint is provided, no assumption are made. Could there be a case that no default resolver is required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am concerned about the other way around; let's say user provides .eth:[email protected]
, what happens to .test
and other TLDs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My view is that in that case, other domains except under .eth TLD should not be resolved, as that is configured by the user. In this particular case, one may assume that provided endpoint which is ti only one can be used for other TLDs. But what is the case if endpoints for two or more TLDs are provided, but not a default endpoint? One option is not to have the default resolver, and the order one is to add all resolvers as default resolvers. Maybe the later behaviour is a better solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is right. I would also like to hear more opinions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if the user doesn't provide a default (i.e. a value without the tld:
part), then names which don't match an endpoint should not be resolved.
For example, if I explicitly start swarm with:
--ens-api .eth:<addr>@geth.ipc --ens-api .test:<addr>@testnet/geth.ipc
I would not expect say .foo
requests to be resolved, rather an error be returned like no ENS endpoint configured to resolve .foo names
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lmars the functionality is now similar, just the error returned from MultiResolver.Resolve should include the information about the TLD, currently it is just an error (var errNoResolver) with "no resolver" message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, so @janos when you have changed the error message please ping, then I can mark this as approved from my side. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a new error type NoResolverError for more verbose error message.
type MultiResolver struct { | ||
resolvers map[string][]Resolver | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need multiple resolvers per TLD if only the first resolution is returned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per requirement in this comment ethereum/go-ethereum#14386 (comment) for sequence of resolvers.
@@ -76,7 +81,7 @@ func (self *Swarm) API() *SwarmAPI { | |||
|
|||
// creates a new swarm service instance | |||
// implements node.Service | |||
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, ensClient *ethclient.Client, config *api.Config, swapEnabled, syncEnabled bool, cors string) (self *Swarm, err error) { | |||
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config) (self *Swarm, err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good simplifying the func interface here, thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. :)
opts := []api.MultiResolverOption{} | ||
for _, c := range config.EnsAPIs { | ||
tld, endpoint, addr := parseEnsAPIAddress(c) | ||
r, err := newEnsClient(endpoint, addr, config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should test for invalid formats before we actually try to connect to ENS? What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function parseEnsAPIAddress does not return error as the format is very simple, permissive in the endpoint part and assumes any value for tld and contract address. I would put format validation much sooner during execution, just after the config load in cmd/swarm.buildConfig. Would that be ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think that would be a good idea.
MultiResolver needs to provide information about TLD that has no resolver configured for.
Thanks @holisticode. @lmars are you still approving the PR, even with the latest changes? |
@@ -101,6 +102,8 @@ func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) { | |||
config = envVarsOverride(config) | |||
//override settings provided by command line | |||
config = cmdLineOverride(config, ctx) | |||
//validate configuration parameters | |||
err = validateConfig(config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shadows the previous assignment of err
which is now not being checked (we should probably avoid named return arguments unless they are really needed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by returning right after the previous error assignment if it is not nil.
} | ||
|
||
if ensaddr := ctx.GlobalString(EnsAddrFlag.Name); ensaddr != "" { | ||
if ensaddr := ctx.GlobalString(DeprecatedEnsAddrFlag.Name); ensaddr != "" { | ||
currentConfig.EnsRoot = common.HexToAddress(ensaddr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should print a deprecation notice here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The depreciation message is handled in checkDeprecated function on line 319.
cmd/swarm/config.go
Outdated
@@ -97,10 +98,15 @@ func buildConfig(ctx *cli.Context) (config *bzzapi.Config, err error) { | |||
config = bzzapi.NewDefaultConfig() | |||
//first load settings from config file (if provided) | |||
config, err = configFileOverride(config, ctx) | |||
if err != nil { | |||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be return nil, err
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, fixed. :( Thank you!
this looks good to me. ready for PR on main repo? |
@zelig PR created ethereum/go-ethereum#15748. |
merged to |
This PR implement a CLI flag that can be repeated to allow multiple ENS
resolvers for different TLDs.
New flag --ens-endpoint can be repeated and accepts value with
format [tld:][contract-addr@]url.
MultiResolver is implemented to support resolutions based on their TLDs.
Each TLD can have multiple resolvers, and the resolution from the
first one in the sequence will be returned. If the TLD does not have its own resolver, a default resolver will be used.
ENSClientConfig is implemented to provide configuration parameters for ens resolvers on Swarm initialization.
Function detectEnsAddr has been moved from cmd/swarm/main.go to swarm/swarm.go.