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

Address metadata registry #926

Merged
merged 4 commits into from
Mar 29, 2018
Merged

Conversation

Arachnid
Copy link
Contributor

@Arachnid Arachnid commented Mar 12, 2018

This PR provides a proposal for an address metadata registry, of use in applications such as ENS, distributed identity systems, and new token contract standards.

See #927 for an example use-case of this standard.

This was referenced Mar 12, 2018

## Provider specification

Providers may implement any subset of the metadata record types specified here. Where a record types specification requires a provider to provide multiple functions, the provider MUST implement either all or none of them. Providers MUST throw if called with an unsupported function ID.
Copy link
Contributor

Choose a reason for hiding this comment

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

For clarity, recommend including the Solidity code for this:

function () { revert; }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solidity implements this automatically now.

function supportsInterface(bytes4 interfaceID) constant returns (bool)
```

The `supportsInterface` function is documented in [EIP 165](https://github.com/ethereum/EIPs/issues/165), and returns true if the provider implements the interface specified by the provided 4 byte identifier. An interface identifier consists of the XOR of the function signature hashes of the functions provided by that interface; in the degenerate case of single-function interfaces, it is simply equal to the signature hash of that function. If a provider returns `true` for `supportsInterface()`, it must implement the functions specified in that interface.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the motivation behind using XOR of the signature IDs rather than a hash of all of the signatures? While I suspect someone can implement the XOR without too much difficulty, keccak hashing of things in the Solidity ecosystem is a well understood problem as it is used everywhere while XOR of first 4 bytes of a keccak hash of a thing is significantly less understood by the average developer.

The following is what the hash might look like, which is pretty familiar to any Ethereum developer at this point and can be done in Solidity or in JavaScript (most common dapp development language).

keccak256("function foo(uint256,bool)", "function bar()", "function zip(string,bytes)")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See EIP 165 for justification. I don't think this is a good place to rehash that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Glanced through that, there was a reference to a Gitter conversation where bytes4 XOR was chosen over bytes32 hash but no details of the contents of that conversation were provided. From my reading of #165, I am not at all convinced that XOR of function IDs is superior to hash of function signatures.

Was there a particular comment that you feel captures the argument over there? It is possible I missed a subtle argument as I was skimming the comments rather than analyzing them in depth.

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 really don't want to get derailed on arguing the merits of an unrelated standard in this EIP. Can you open a discussion on 165 instead? It's unlikely we can make a change at this point, though, since it's already widely deployed (eg, on ENS for one).

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, now that I have read EIP 165 and realize that this section is just a watered down summary of 165 I no longer want to press the bytes32 vs XOR thing here.


The `supportsInterface` function is documented in [EIP 165](https://github.com/ethereum/EIPs/issues/165), and returns true if the provider implements the interface specified by the provided 4 byte identifier. An interface identifier consists of the XOR of the function signature hashes of the functions provided by that interface; in the degenerate case of single-function interfaces, it is simply equal to the signature hash of that function. If a provider returns `true` for `supportsInterface()`, it must implement the functions specified in that interface.

`supportsInterface` must always return true for `0x01ffc9a7`, which is the interface ID of `supportsInterface` itself.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the point of this? At first blush it feels like it is just a clever little thing to chuckle at in the spec, but not something that anyone would ever need for anything. I'm guessing the thought is that you can call this to check if supportsInterface is available at all (with the expectation that it will return false by default) but I believe there is currently a "bug" in Solidity that makes the default return garbage (which evaluates to false 1/2^256 times). Even if this is "fixed" (unclear if that is planned or not), it feels weird probing a contract like this.

Is there some other reason for this MUST?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, recommend changing must to **MUST**.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also see 165 and 137; the idea is that it lets a generic caller determine if the contract implements supportsInterface in the first place.

Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned over in #165 (and I didn't see a rebuttal, though I may have missed it) older Solidity (based on discussion there it sounds like this has since been fixed) contracts will return garbage data by default (meaning true or false). Thus if someone calls supportsInterface on such a contract they may (likely) get back true even though it doesn't actually support the interface. One recommendation was to have both a positive and a negative check function to address this.

Copy link
Contributor

Choose a reason for hiding this comment

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

It appears that 165 addresses this problem with:

true when interfaceID is 0x01ffc9a7 (EIP165 interface)
false when interfaceID is 0xffffffff

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As mentioned over in #165 (and I didn't see a rebuttal, though I may have missed it) older Solidity (based on discussion there it sounds like this has since been fixed) contracts will return garbage data by default (meaning true or false).

Only if they implement a fallback that doesn't throw - which this standard explicitly prohibits.

provider[msg.sender] = _provider;
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

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

Recommend including an example provider as well that at least implements the required supportsInfercae code (and shows how to do the function signature hashing in Solidity).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, though callers don't need to do the function hashing, just embed the appropriate constants (unless we can trust solidity to optimise those out, even if optimisation is turned off?)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think there is value in showing a user how to do the XOR, hashing and byte chopping in code, and Solidity is the language that we can be certain all readers of these understand.

Copy link
Contributor Author

@Arachnid Arachnid Mar 12, 2018

Choose a reason for hiding this comment

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

If Solidity doesn't optimise-away the hashing at compile-time, though, this is going to be a significant waste of gas.

Edit: And in any case this is likely something that should be demoed in 165.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would be OK (though not quite as satisfied) with an example written in JS if you think that is more reasonable. Solidity is just the "common language". I would not recommend people actually do the hashing in Solidity with each contract call.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again, I don't think this is the place to do it - this is just a user of EIP165; any examples should probably be there.

Copy link
Contributor

Choose a reason for hiding this comment

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

As a developer who didn't know of EIP 165's prior to reading this EIP, I was surprised to find it lacking an example for the "other side". If you think this EIP should depend on 165, then I recommend including such a dependency in the EIP and indicating how the two are connected to each other. In general, if an EIP doesn't reference any other EIPs, then I assume it can be consumed on its own (which is what I tried to do when reading this EIP) and it seems that your intent is that this EIP is not consumed on its own.

Copy link
Contributor

Choose a reason for hiding this comment

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

And of course after saying that, I re-read this EIP and found it did mention EIP 165...

@fulldecent
Copy link
Contributor

Currently, #820 supports a level of indirection where an authorized third party can set metadata for an address. I expect this level of indirection will be demanded by other users of this proposed standard.

I am not sure if an event is necessary here. But a good reason for or against it should be presented in the rationale.


This standard does not include a strong use case statement. The cited motivation is #820 and #181. The former is just an idea, it is not deployed, and no statement is made citing usage statistics of the latter.

I think a very strong use case statement, supported by representative third parties is essential to a mergable EIP.

@Arachnid
Copy link
Contributor Author

Arachnid commented Mar 12, 2018

Currently, #820 supports a level of indirection where an authorized third party can set metadata for an address. I expect this level of indirection will be demanded by other users of this proposed standard.

This is supported - you just set your provider to be one that supports this indirection. If your provider supports #927, you get this basically for free.

I am not sure if an event is necessary here. But a good reason for or against it should be presented in the rationale.

You're right, I'll add an event.

This standard does not include a strong use case statement. The cited motivation is #820 and #181. The former is just an idea, it is not deployed, and no statement is made citing usage statistics of the latter.

I think a very strong use case statement, supported by representative third parties is essential to a mergable EIP.

See also #927 for an example use-case. I don't think the current justification is weak, personally.

function supportsInterface(bytes4 interfaceID) constant returns (bool)
```

The `supportsInterface` function is documented in [EIP 165](https://github.com/ethereum/EIPs/issues/165), and returns true if the provider implements the interface specified by the provided 4 byte identifier. An interface identifier consists of the XOR of the function signature hashes of the functions provided by that interface; in the degenerate case of single-function interfaces, it is simply equal to the signature hash of that function. If a provider returns `true` for `supportsInterface()`, it must implement the functions specified in that interface.
Copy link
Contributor

Choose a reason for hiding this comment

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

This should link to the draft of EIP 165, not the issue: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md

function supportsInterface(bytes4 interfaceID) constant returns (bool)
```

The `supportsInterface` function is documented in [EIP 165](https://github.com/ethereum/EIPs/issues/165), and returns true if the provider implements the interface specified by the provided 4 byte identifier. An interface identifier consists of the XOR of the function signature hashes of the functions provided by that interface; in the degenerate case of single-function interfaces, it is simply equal to the signature hash of that function. If a provider returns `true` for `supportsInterface()`, it must implement the functions specified in that interface.
Copy link
Contributor

Choose a reason for hiding this comment

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

After reading EIP 165 (draft rather than the GitHub issue, which was much harder to follow), I am now confused why this entire section exists. It appears to just be re-hashing what EIP 165 says, but with less context, less detail and fewer examples. Why not just say that providers are defined by EIP 165 and leave it at that?

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 thought a brief description would be useful so that someone who only wants to implement it doesn't need to read all of 165, too.

Copy link
Contributor

Choose a reason for hiding this comment

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

I need to step away and think a bit more to avoid curve fitting my personal experience, but my gut right now is telling me that the fact that there was a bunch of text rather than just a link resulted in me ignoring the link and reading just the text, which unfortunately is lacking in the detail I would expect from an EIP.

@Arachnid
Copy link
Contributor Author

@MicahZoltu Another potential use-case for this registry: returning URIs to DSLs for #719.

@fulldecent
Copy link
Contributor

These use cases are helpful to create an interface. But for a standard, I think the use cases should be supported by citations to deployed contracts that would benefit from this standard, upcoming projects that are launching and can use it, and statements made by people launching those projects.

This is just my thought and it is NOT the current EIP-1 process.

@Arachnid
Copy link
Contributor Author

These use cases are helpful to create an interface. But for a standard, I think the use cases should be supported by citations to deployed contracts that would benefit from this standard, upcoming projects that are launching and can use it, and statements made by people launching those projects.

This is just my thought and it is NOT the current EIP-1 process.

What would be the benefit of raising the bar to standardising an interface like this? It seems to me it would just lead to people doing things on an ad-hoc basis for longer, and the deployment of multiple slightly-incompatible versions of effectively the same thing.

@fulldecent
Copy link
Contributor

Regarding "Doing things on an ad-hoc basis for longer."

Zero has been done on an adhoc basis -- most "standards" are proposed interfaces to things that don't exist. When people have skin in the game and spend a few Finney on deploying something then it becomes worthwhile to discuss standardizing.

@Arachnid
Copy link
Contributor Author

This is a courtesy notice to let you know that the format for EIPs has been modified slightly. If you want your draft merged, you will need to make some small changes to how your EIP is formatted:

  • Frontmatter is now contained between lines with only a triple dash ('---')
  • Headers in the frontmatter are now lowercase.

If your PR is editing an existing EIP rather than creating a new one, this has already been done for you, and you need only rebase your PR.

In addition, a continuous build has been setup, which will check your PR against the rules for EIP formatting automatically once you update your PR. This build ensures all required headers are present, as well as performing a number of other checks.

Please rebase your PR against the latest master, and edit your PR to use the above format for frontmatter. For convenience, here's a sample header you can copy and adapt:

---
eip: <num>
title: <title>
author: <author>
type: [Standards Track|Informational|Meta]
category: [Core|Networking|Interface|ERC] (for type: Standards Track only)
status: Draft
created: <date>
---

@gcolvin gcolvin merged commit a5a6600 into ethereum:master Mar 29, 2018
@Arachnid Arachnid deleted the addressmetadata branch March 29, 2018 09:12
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.

4 participants