ethereum/EIPs

ERC 1497: Evidence Standard

satello opened this issue · 25 comments

EIP 1497
Title: Evidence Standard
Status: Draft
Type: Informational
Category: ERC
Authors: Sam Vitello <sam@kleros.io>, Clément Lesaege <clement@kleros.io>, Enrique Piqueras <enrique@kleros.io>
Created: 2018-10-16

Abstract

The following describes the standards for MetaEvidence and Evidence for dispute resolution. Evidence is provided by a participant in a dispute in order to support their assertion. MetaEvidence gives context to the dispute so that arbitrators are able to accurately and fairly evaluate it. This standard follows ERC 792 and references Arbitrator and Arbitrable contracts.

Motivation

Standardizing MetaEvidence and Evidence allows interoperability between Arbitrable DApps (DApps where disputes can arise) and Arbitrator DApps (DApps which can be used to resolve disputes). It allows these applications to easily switch from one arbitration service to another, or to let their users decide which arbitration service to use without having to spend time to integrate with all of them. MetaEvidence is required to provide the context of the dispute. Evidence allows for dispute participants to submit extra information for the arbitrators.

The ERC792 standardizes the way the smart contracts interact with each other while this standard is made to standardize the way the interfaces interact in the context of disputes.

Specification

MetaEvidence

MetaEvidence provides the context of the dispute, the question the arbitrators have to answer, the human readable meanings of rulings and specific modes of display for evidence.

NOTE: Each dispute includes only one piece of MetaEvidence, however, the same MetaEvidence can be used for multiple disputes.
NOTE: It is up to the Arbitrable contract to determine how MetaEvidence is submitted and assigned to a dispute.
NOTE: In some use cases, MetaEvidence is all that the Arbitrator will need in order to make a ruling.
NOTE: All MetaEvidence fields are optional. An Arbitrator interface should have defaults for every field. However, not supplying contextual fields may affect the arbitrator’s ability to make an accurate ruling. Not supplying hash fields meant to secure the integrity of the data may result in arbitrators being warned that the data could have been altered.

Events

MetaEvidence
MetaEvidence has to be created before a dispute can arise. The MetaEvidence event includes an identifier used to link the MetaEvidence to a dispute and the _evidence reference is a URI to a JSON file, specified below, whose name is the multihash hash of the file with no file type extension. The JSON file should have all insignificant whitespace removed before hashing.

To be emitted when MetaEvidence is submitted:

event MetaEvidence(uint indexed _metaEvidenceID, string _evidence);

JSON

The MetaEvidence JSON file includes the following properties:

{
  "fileURI": string,
  "fileHash": string,
  “fileTypeExtension": string,
  "category": string,
  "title": string,
  "description": string,
  "aliases": {
    [string]: string
  },
  "question": string,
  "rulingOptions": {
    "type": string,
    "precision": number,
    "titles": [],
    "descriptions": []
  },
  "evidenceDisplayInterfaceURI": string,
  "evidenceDisplayInterfaceHash": string,
  "dynamicScriptURI": string,
  "dynamicScriptHash: string
}

fileURI

The URI that leads to a natural language contract, agreement, or primary document that is the basis of the dispute. The file name should be the multihash hash of the resulting file. If this is not possible use fileHash.

Example: "/ipfs/QmUQMJbfiQYX7k6SWt8xMpR7g4vwtAYY1BTeJ8UY8JWRs9”

fileHash

The multihash hash of the primary document file. This may not be included for dynamic or mutable evidence. Not including the hash, either as the file name or in this property, may result in arbitrators being made aware that the evidence could have been altered.

Example: “QmUQMJbfiQYX7k6SWt8xMpR7g4vwtAYY1BTeJ8UY8JWRs9”

fileTypeExtension

The file type extension of the resulting file. This can be used by an Arbitrator interface to display the file.

Example: “pdf”

category

A short (one word or phrase) high level identifier for the type of dispute. E.g. “Curated List”, “Oracle” or “Escrow”.

Example: "Escrow"

title

Title that summarizes the relationship between the participants.

Example: "Alice Builds a Webpage for Bob"

description

Description of the relationship between the participants. Here is where more detail can be provided so that arbitrators can fully understand the context in which the dispute arose. It can be a summary of the terms of the primary document file, and/or include other contextual information.

Example: "Alice is hired by Bob as a contractor to create a website for his company. When completed, the site will be hosted at https://my-site.com."

aliases

A mapping that can be used by the Arbitrator interface to translate each given key to the supplied value. For example, ETH addresses can be mapped to human readable terms to make the dispute easier to understand.

Example:

{
    "0x56b2b5C88C9AC1D0E5785ED1A7c7B28173F5eE1b": "Alice",
    "0x8961286757C764a4a6Be9689649BA9E08DBaca4a": "Bob"
}

question

The question that arbitrators have to answer.

Example: "Is the website compliant with the terms of the contract?"

rulingOptions

Information about the ruling options to provide clarity on the available rulings to arbitrators.

Indexes of titles and descriptions map to the ruling options of the Arbitrable contract. Ruling indexing starts at ruling option 1 (rulingOptions.titles[0] corresponds to ruling option 1 in the Arbitrable contract). The ruling option 0 is always reserved for “Refuse to Arbitrate” and should not be included in the array. The Arbitrator interface can specify the specific title and description used for the “Refuse to Arbitrate” ruling.

type is used to indicate to the arbitrator interface how a ruling should be made. There are 5 basic types that an arbitrator interface are expected to support. If a type is not specified, the arbitrator interface should default to type single-select. Arbitrator interfaces can choose to support other custom types.

  • single-select: arbitrators select one answer among the provided options.
  • multiple-select: arbitrators can select any number of the provided options.
  • uint: arbitrators input an unsigned integer.
  • int: arbitrators input a signed integer.
  • string: arbitrators enter a string. String must fit into bytes32.

precision is used for ruling types int and uint to indicate the number of decimal places a ruling contains.

Example:

{
    "type": "single-select",
    “titles”: [“Yes”, “No”],
    “descriptions”: [
         "The website is compliant. This will release the funds to Alice.",
         "The website is not compliant. This will refund Bob."
    ]
}

evidenceDisplayInterfaceURI

The URI to a display interface that should be used to render the evidence for arbitrators. The Arbitrator interface should use an iframe to render the display interface. Data can be passed to the custom display interface with query parameters or with browser based approaches such as window.postMessage.

NOTE: Arbitrator interfaces should still have a default way to display evidence, as not all evidence will use a custom evidence display interface.
NOTE: Arbitrator interfaces should take security precautions when injecting the evidence display interface code into their page. The iframe used to render the external interface should be secured properly with a sandbox or other means of disabling functionality that could pose a security risk to the interface or users. For example, an interface should disallow the injected web3 object from MetaMask or a different browser wallet from requesting signatures from the user. This can be accomplished by using a sandbox to disallow the external interface from retaining its origin (and therefore using the browser’s built in security features to block API requests), or by removing methods such as sign and personalSign from the injected web3 object.

Example: "https://my-site.com/evidence-display/escrow"

evidenceDisplayInterfaceHash

Like fileHash for fileURI.

Example: “QmUQMJbfiQYX7k6SWt8xMpR7g4vwtAYY1BTeJ8UY8JWRs9”

dynamicScriptURI

The URI of a script that can be run when the MetaEvidence is fetched by an arbitrator interface in order to make dynamic updates. The script should expose a function getMetaEvidence that returns JSON, which should be merged with the original MetaEvidence JSON.

NOTE: Arbitrator interfaces should take security precautions when running an external script. A script should never be run directly inline as this would give the script full access to the DOM and make calls on behalf of the arbitrator. Instead the script should be run in a sandbox such as an iframe so that the scope is limited.

Example: "/ipfs/QmUQMJbfiQYX7k6SWt8xMpR7g4vwtAYY1BTeJ8UY8JWRs9”

dynamicScriptHash

Like fileHash for fileURI.

Evidence

Arbitrable contracts emit an event that contains a reference to an evidence JSON file when new evidence is submitted.

Events

Evidence

The event log should include the Arbitrator contract, an identifier for the EvidenceGroup it belongs to, the address of the submitting party, and reference to the evidence itself. The evidence reference is a URI to a JSON file, specified below, whose name is the multihash hash of the file with no file type extension. The JSON file should have all insignificant whitespace removed before hashing.

NOTE: An EvidenceGroup is used to link individual pieces of evidence and eventually to link the entire grouping of evidence to a dispute. An Evidence Group must have it's own unique identifier so that Evidence can be submitted before a dispute has been raised.

To be triggered when evidence is submitted:

event Evidence(Arbitrator indexed _arbitrator, uint indexed _evidenceGroupID, address indexed _party, string _evidence)

JSON

The Evidence JSON file includes the following properties:

{
  "fileURI": string,
  "fileHash": string,
  "fileTypeExtension": string,
  "name": string,
  "description": string
}

fileURI

Like the fileURI for MetaEvidence.

Example: “/ipfs/QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc”.

fileHash

Like the fileHash for MetaEvidence.

Example: “QmWQV5ZFFhEJiW8Lm7ay2zLxC2XS4wx1b2W7FfdrLMyQQc”.

fileTypeExtension

Like the fileTypeExtension for MetaEvidence.

Example: “pdf”.

name

What the piece of evidence should be called.

Example: “Email clarifying the terms of the contract.”

description

A brief description of what the evidence contains. Can also include any necessary context to understand the evidence.

Example: “This is an email sent to Alice from Bob that clarifies that the checkout screen can be integrated with the catalog page.”

Dispute

A dispute must include a MetaEvidence and an EvidenceGroup. A dispute can have one MetaEvidence and many pieces of Evidence that are linked together by an EvidenceGroup.

Events

Dispute
The Dispute event is raised when a dispute is created to link the proper MetaEvidence and EvidenceGroup to the dispute. The event includes a reference to the Arbitrator, a unique identifier for the dispute itself, the identifier used to look up the MetaEvidence event log and the identifier of the EvidenceGroup that can be used to look up all evidence submitted in the grouping.

To be emitted when a dispute is created.

event Dispute(Arbitrator indexed _arbitrator, uint indexed _disputeID, uint _metaEvidenceID, uint _evidenceGroupID);

Rationale

  • A series of hashes are used to verify that evidence has not been tampered with. The blockchain events can maintain integrity of the address of the submitter, the date of submission, and the hash of the MetaEvidence or Evidence file. Hashes included in the JSON file of the MetaEvidence or Evidence can then be used to verify that the evidence has not changed since submission.
  • JSON objects are a standard way to structure and share data on the web. They provide structural flexibility to represent any type of data, can maintain integrity through use of hashing, and are easily interpreted.
  • It is not practical to store all type of evidence on the blockchain, so links to off-chain evidence are broadcasted instead. URIs are compatible with classical web URLs as well as decentralized web storage such as IPFS and SWARM. Both partially and fully decentralized dapps can be supported with URIs.
  • The fileURI and fileHash are two separate variables in the MetaEvidence and Evidence JSON to maximize flexibility on the types of links that can be used (as opposed to only supporting the hash as the file name). For example, if the evidence is a news article or some other public resource, the hash needs to be included separately.
  • dynamicScriptURI was chosen instead of a callback because it gives Arbitrable parties the ability to provide audibility. The script can be publicly posted with the included hash so that arbitrators can verify that the same edits are being made for everyone who runs the script. It is harder to prove this on a privately hosted callback.

Implementations

Smart Contract Examples

JSON File Examples

Evidence Display Interface Examples

Dynamic Script Examples

I have updated the standard by adding Evidence Groupings to the Evidence submission and Dispute creation events. Previously, Evidence was linked directly to a disputeID. This restricted Evidence from being submitted before a dispute had been raised and the disputeID created. Now Evidence can be submitted at any time, and will be linked to a dispute by the Dispute event (raised when a dispute is created) via a evidenceGroupID.

Evidence:

Is fileTypeExtension required? Maybe it can be derived from: https://en.wikipedia.org/wiki/MIME_type

(as a security practice, do not rely on user-provided input, is it ZIP or PDF or HTML Poc||GTFO)

MetaEvidence:

title, question, category, description - too many fields, repetetive.

rulingOptions, type, single, multiple - I'd like to add number, value, range, ratio or proportion... Worried it is getting out of hand, if in doubt simplify.

aliases - not necessary, can live without it. ENS will provide names.

evidenceDisplayInterfaceURI - all evidence is hosted on IPFS or centralized servers, just open in a browser, do I need this info?

dynamicScriptURI - too complicated. Just submit new MetaEvidence

selfHash - someone who modifies evidence can modify selfHash as well, I don't understand what is the point

Meta MetaEvidence

#792 is using human-readable names such as Dispute, Decision, Appeal, Ruling

My suggestion would be to replace geeky sounding MetaEvidence with DisputeInfo or ArbitrationInfo or simply Dispute or Arbitration or Case or Matter (legal language)


EDIT: Noticed Dispute already exists. MetaEvidence is nothing else than DisputeInfo - definitely merge into one, simplify.

EDIT:

If it is not possible to use multihash for the name of the file, use the selfHash field described below.

If it is not possible to use multihash for the name of the file:

  1. use the selfHash for the name of the file?
  2. store multiHash as selfHash?

(previous comment about someone replacing content and validating hashes remain valid)

EDIT: MetaEvidenceall fields optional, Evidence all fields optional too?

EDIT: No extension:

The evidence reference is a URI to a JSON file, specified below, whose name is the multihash hash of the file with no file type extension.

Or extension: https://github.com/kleros/kleros-interaction/blob/96b34176090e3a17d5208f3093ec15a4482d7c43/contracts/standard/arbitration/IArbitrable.sol#L38


I'm literally working on the hackathon project kleros/hackathon#1 and I'm likely to have more thoughts after completion. Will update this post or submit a new comment.

  • fileTypeExtension is not required. If the file includes the MIME type it can be derived by the arbitrator interface that way. None of the fields are required. However, not including some fields may cause an Arbitrator interface to be unable to display a dispute.

  • title, question, category, description all have different purposes so they are not redundant. It is not required that you use them all if they are not relevant to the dispute.

  • rulingsOptions.type has been updated to have a basic set of types ['single-select', 'multiple-select', 'uint', 'int', 'string']. It is not meant to be an exhaustive list of types, just a basic set that all Arbitrator interfaces can be expected to support.

  • aliases: If you derive names another way you do not need to use it.

  • evidenceDisplayInterfaceURI: Evidence can be hosted on a centralized or decentralized platform.

  • dynamicScriptURI: For disputes that will have dynamic content it adds bloat and extra gas to have to continually emit new MetaEvidence. Also for some use cases the data might be too dynamic to continually update it on chain. It is much simpler, less expensive and more flexible to handle it off chain.

  • selfHash: Yes you are right, this will not work. I have changed it so that hashes must be in the file name.

the identifier of the MetaEvidence event that will provide the URI to the MetaEvidence

event Dispute(Arbitrator indexed _arbitrator, uint indexed _disputeID, uint _metaEvidenceID, uint _evidenceGroupID);

Suggestion (assuming we were using IPFS)

string _metaEvidenceHash

If we were using IFPS, we could simply use the hash, instead of the event id... I'm not that good with Ethereum events and accessing their IDs, I thought I'll mention that.

Real-world usage: https://github.com/kleros/kleros-interaction/blob/1ada4bf9d2cc024c162257def03763ad6111c0ff/contracts/standard/arbitration/MultipleArbitrableTokenTransaction.sol#L283

emit Dispute(arbitrator, transaction.disputeId, _transactionID, _transactionID);

Using _transactionID for both _metaEvidenceID and _evidenceGroupID 🧐 Maybe _evidenceGroupID should be 0, appeal becomes 1, appeal appeal becomes 2...


EDIT:

From my previous comment

#792 is using human-readable names such as Dispute, Decision, Appeal, Ruling

My suggestion would be to replace geeky sounding MetaEvidence with DisputeInfo or ArbitrationInfo or simply Dispute or Arbitration or Case or Matter (legal language)

Noticed Dispute already exists. MetaEvidence is nothing else than DisputeInfo - definitely merge into one, simplify.

https://github.com/kleros/kleros-interaction/blob/1ada4bf9d2cc024c162257def03763ad6111c0ff/contracts/standard/arbitration/MultipleArbitrableTokenTransaction.sol#L127

Link to the meta-evidence.

I think we need to simplify and agree:

  • Link (URI) to MetaEvidence
  • IPFS hash of MetaEvidence
  • ID of MetaEvidence

Otherwise, it is not obvious, not clear, error-prone.


EDIT:

The MetaEvidence event includes an identifier used to link the MetaEvidence to a dispute and the _evidence reference is a URI to a JSON file, specified below, whose name is the multihash hash of the file with no file type extension.

I would like to submit that JSON to IPFS.

I know that library written by @satello - https://archon.readthedocs.io/en/latest/ipfs.html - is accepting the following URI schemes:

/ipfs/Qm...../foo/bar
ipfs:/ipfs/Qm...../foo/bar
fs:/ipfs/Qm...../foo/bar

https://github.com/ipfs/ipfs

browsers or extensions can learn to use the ipfs:// URL or dweb:/ipfs/ URI schemes directly

(I will probably use ipfs:// with double slash, just like https://, https:// and ftp://)

At this stage I'm unsure if multihash hash is compatible with IPFS naming. Maybe. Could be. Unsure. I've spent already WAY TOO MUCH time trying to decypher what really is required and what is the minimal viable use case. This can (and should) be simplified and wider user adoption is desired.


CC @clesaege for visibility.

Suggestion (assuming we were using IPFS)
string _metaEvidenceHash

If we were using IFPS, we could simply use the hash, instead of the event id... I'm not that good with Ethereum events and accessing their IDs, I thought I'll mention that.

We cannot assume that Evidence will be hosted using IPFS or another storage that produces/verifies data integrity via hashes. The standard needs to encapsulate all use cases.

Using _transactionID for both _metaEvidenceID and _evidenceGroupID 🧐 Maybe _evidenceGroupID should be 0, appeal becomes 1, appeal appeal becomes 2...

evidenceGroupID is used to link pieces of evidence together, and then to link all of the evidence to a dispute. You would still want evidence from previous appeals to be linked to the same dispute.

Noticed Dispute already exists. MetaEvidence is nothing else than DisputeInfo - definitely merge into one, simplify.

We cannot merge MetaEvidence into Dispute. MetaEvidence is separate and can be (should be in most cases) submitted before a dispute has been raised.

browsers or extensions can learn to use the ipfs:// URL or dweb:/ipfs/ URI schemes directly

This is for browsers. I chose these formats from here: ipfs/kubo#1678 (comment).

This seemed to be the most convincing "standard" for IPFS URIs. Note that the issue is still open so this is subject to change. If you want to continue discussing this we can over at https://github.com/kleros/archon/issues

  • You created the standard
  • You wrote a utility library
  • You linked to the existing code samples

The library and the code become de facto a reference implementation.


In IPFS filename is the hash

Here you suggest using multihash.

Prior to reading, I have never heard of multihash.

Keccak3 is de facto a hashing standard on Ethereum, whoever is to use the standard, is likely to have web3 and Keccak3 already in place: https://ethereum.stackexchange.com/questions/550/which-cryptographic-hash-function-does-ethereum-use

Do you want the standard to become bigger than just Ethereum or just futureproofing?

My main principle remains the same:

Simplicity = wider adoption.

Let's see what other developers working on implementing the standard will tell, what is their feedback.

For the time being, I will focus on finishing the hackathon project.

(money well spent, incentivizing people to look at the standard)

FYI: While working on the hackathon and evaluating the standard I’ve created something simple: https://genesis.re/kleros-metaevidence-metahash/ “Making uploading to IPFS easier since 2019”


EDIT:

http://jonathanpatrick.me/blog/ethereum-compressed-text

Log storage is the ideal place to store text in the Ethereum blockchain. Contract state could be used, but it is more expensive and doesn't really offer any advantages. There is no reason why contract logic would need to access a blob of text. Data stored in the log can only be accessed externally, but that is fine for this use-case.

Do you think it will be possible to have completely on-chain arbitrator? On-chain cannot read emit Event. Maybe explain the rationale behind emitting Events, maybe explain the rationale behind the various points of the design.

Simplicity = wider adoption.

I understand what you are saying, but for a standard it is more important that it is future proof than being simple/easy to adopt. That being said if there are ways to simplify the standard without compromising functionality than I am all for it. Adoption is important, but it is more important that the standard can work for as many use cases as possible or else it will quickly reach it's limits and won't be a useful standard. You can always use a simplified version of the standard JSON if you do not need all of the different fields.

In IPFS filename is the hash
Here you suggest using multihash.
Prior to reading, I have never heard of multihash.
Keccak3 is de facto a hashing standard on Ethereum.

IPFS uses multihash. Multihash is used because it allows different hash functions to co-exist. Actually Ethereum hashing standards are confusing already. Solidity uses a non-standard implementation of keccak256 which is not compatible with your out of the box sha3 (solidity.keccak256 != web3.keccak256). Multihash can encompass most of the different hashing functions people may want to use. If you use IPFS you don't need to worry about doing any hashing yourself.

Do you think it will be possible to have completely on-chain arbitrator? On-chain cannot read emit Event. Maybe explain the rationale behind emitting Events, maybe explain the rationale behind the various points of the design.

What would be the purpose of an on-chain arbitrator? You always need some end user to give the ruling, regardless of whether they are reading the dispute information from the contract state or the event logs. All of the advantages that are in the passage you quoted are true here and I don't see any advantages to using storage in this use case. The contract itself cannot make a ruling so it has no need to access the Evidence or MetaEvidence.

About IPFS and multihash: https://github.com/ipfs/specs/tree/master/architecture#21-multihash-and-upgradeable-hashing

(didn't know about it)

MetaEvidence, MetaHash, it all sounds so meta.


I agree that most likely there is no need for on-chain arbitrator. If AI gets sophisticated enough, I'll build their own toolchain to read Events or use the Archon library.


EDIT: Still confused.

image

We managed to agree that events are accessed off-chain. How on-chain code can know the identifier of the event?


Copy paste from the previous comments:

Hackathon money well spent, incentivizing people to look at the standard.

Let's see what other developers working on implementing the standard will tell, what is their feedback.

It is referring to _metaEvidenceID. You use _metaEvidenceID to look up the MetaEvidence event log. The contract itself doesn't need to know the _metaEvidenceID. I will clear up the wording there.

And yes the more eyes we get on this the better!

RELATED: Have you heard of https://opentimestamps.org/ https://en.wikipedia.org/wiki/OpenTimestamps ?

Committing to a value, ensuring that piece of evidence existing before a certain time.


What are your thoughts about going IPFS only?

This ERC1497 is specific to Ethereum (emitting events for example) and I'm leaning towards establishing IPFS as standard.

(dropping support for traditional servers)

Rationale: no need to store hash, as the filename is the hash. Audience technical enough to handle the standard will be able to handle IPFS with breeze.

Shameless plug - https://genesis.re/kleros-metaevidence-metahash/ - making it easier 😇

lidel commented

🚗 💨 some drive-by comments from IPFS :)

On IPFS Addressing

This is for browsers. I chose these formats from here: ipfs/go-ipfs#1678.

This seemed to be the most convincing "standard" for IPFS URIs. Note that the issue is still open so this is subject to change.

Linked issue is super old (2015), we will close it to decrease noise (sorry!).
Since then, we switched to ipfs://, ipns:// and dweb:/ to improve URL/URI interop, ease adoption and unblock browser integration. Latest IPFS addressing standards for web browsers can be found at ipfs/in-web-browsers/ADDRESSING.md.

That being said, in contexts that do not require strict URI/URL interop, things can be simplified:

  • If you want to only support immutable IPFS, raw {cid} should suffice
  • If you want to support mutable pointers at some point, then /ipfs/{cid} is a better idea, as you can add support for /ipns/{keyid} in the future
  • If you want to be able to support not only IPFS, but also other namespaces, dweb:/ipfs/{cid} URI may be the most future-proof way (dweb:/somethingelse/{hash})

On CIDs and Multihashes

At this stage I'm unsure if multihash hash is compatible with IPFS naming.
About IPFS and multihash [..]

fyi IPFS wraps raw Multihash in Content IDentifier (CID) these days:
https://github.com/multiformats/cid#versions:

cidv0 ::= <multihash-content-address>
cidv1 ::= <multibase-prefix><cid-version><multicodec-content-type><multihash-content-address>

tl;dr:
CIDv0 is implicitly versioned, equal to raw Multihash (in text form always encoded in Base58btc).
CIDv1 is explicitly versioned, text form can be encoded with arbitrary base (multibase prefix is dropped in binary form), and includes multicodec to indicate the type of content refered by multihash.

If you want your spec to be better aligned with IPFS concepts, it should be worded around CIDs, not raw Multihashes. Referring to content via raw multihash is fine and will still work, but you may consider some benefits of custom base and knowing content type before it is fetched.

Example: CIDv1 encoded in Base32 can be used in authority part of URLs:
https://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq.ipfs.dweb.link/wiki/

Refs.

Hi @lidel. Thanks for the clarifications and suggestions. For the purposes of this standard it is not necessary to spell out the accepted URI formats in the standard itself, as these may change over time and different interfaces will have different requirements, but this is great discussion for people trying to implement an interface that will support IPFS.

CIDs are an interesting idea. We could then remove fileTypeExtension from the respective JSON schemas and not have to worry about missing content-types. My biggest concern is that it creates a much higher threshold for implementation. As @marsrobertson pointed out in earlier comments, just doing a standalone multihash was a little bit burdensome. Requiring all hashes to be wrapped in a CID adds another level of complexity.

lidel commented

Cool, just wanted to put the concept of a CID on the radar in case its useful for this or future standards.

Going with raw multihash should be fine if you don't care about CID, or as long you also store DAG type or all data is in the same DAG format. For example, CIDv1 of IPFS files can be derived from multihash alone, if needed.

There are 2 typos in the metaEvidence json:

  1. L4 “fileTypeExtension": string, => "fileTypeExtension": string,
  2. L21 "dynamicScriptHash: string => "dynamicScriptHash": string

Follow-on Proposal

We are making some additions to this proposal in a backwards-compatible fashion.

Motivation

Almost 3 years have passed since this proposal was created and we learned a lot about what it takes to build applications on both the Arbitrator and the Arbitrable side. As it currently is, the standard leaves a lot of unanswered questions that could lead to issues down the road.

To alleviate this problem, we are adding some fields and recommended ways of solving common problems when building arbitrable and arbitrator applications.

Specification

MetaEvidence

Example:

{
  "type": "single-select",
  "titles": ["Yes", "No"],
  "descriptions": [
    "The website is compliant. This will release the funds to Alice.",
    "The website is not compliant. This will refund Bob."
  ],
  "arbitratorChainID": 1,
  "arbitrableChainID": 100,
  "arbitrableInterfaceURI": "https://my-awesomme.dapp.io/item/1234",
  "dynamicScriptRequiredParams": [
    "arbitrableChainID",
    "arbitrableJsonRpcUrl"
    "arbitrableContractAddress",
  ],
  "evidenceDisplayInterfaceRequiredParams": [
    "disputeID",
    "arbitrableContractAddress",
    "arbitratorContractAddress",
    "arbitratorChainID",
    "arbitratorJsonRpcUrl"
  ],
  "_v": "1.0.0"
}

_v

MetaEvidence JSON files SHOULD have a special field explicitly indicating their version:

{
  // ...
  "_v": string,
}

Identifies which version of the standard the files refer to. This enables interfaces and consumers to support multiple versions at the same time.

The changes made in this follow-on document constitute the 1.0.0 version. Any additional changes made SHOULD be versioned following SemVer.

Whenever _v field is missing, it SHOULD be considered a document of the first iteration, conversely _v: "0" (without the SemVer notation).

arbitrableChainID

{
  // ...
  "arbitrableChainID": number,
}

The ID of the chain (as defined by EIP-155) in which the arbitrable application is running.

If omitted, the Arbitrable side SHOULD implicitly be considered to be on the same chain as the Arbitrator.

arbitratorChainID

{
  // ...
  "arbitratorChainID": number,
}

The ID of the chain (as defined by EIP-155) in which the arbitrator for the arbitrable application is running.

When present, the Arbitrator interface MUST validate whether it is currently connected to the same chain ID or not. If there is a mismatch, the interface SHOULD consider the MetaEvidence invalid.

If omitted, the Arbitrable side can implicitly be connected to arbitrators on any chain.

arbitrableInterfaceURI

{
  // ...
  "arbitrableInterfaceURI": string,
}

An URI pointing directly to the arbitrable item on the arbitrable application to make it easier for jurors to view the full context of what originated the dispute.

dynamicScriptRequiredParams

{
  // ...
  "dynamicScriptRequiredParams": string[],
}

The name of the parameters that are required to be injected into the script defined in dynamicScriptURI for it to work properly. It MUST be a subset of the names of the Injected Parameters described later in this proposal.

When provided, only the required parameters SHOULD be injected. If omitted, all parameters MUST be injected.

evidenceDisplayInterfaceRequiredParams

{
  // ...
  "evidenceDisplayInterfaceRequiredParams": string[],
}

The name of the parameters that are required to be injected into the interface defined in evidenceDisplayInterfaceURI for it to work properly. It MUST be a subset of the names of the Injected Parameters described later in this proposal.

When provided, only the required parameters SHOULD be injected. If omitted, all parameters MUST be injected.

Injected Parameters

The script defined by dynamicScriptURI and the interface defined by evidenceDisplayInterfaceURI MAY both require parameters to work properly. The code consuming them MUST inject at least the following parameters by default:

  • disputeID: string: the ID of the dispute in the arbitrator contract;
  • arbitratorContractAddress: string: the address of the arbitrator contract;
  • arbitratorChainID: number: the ID of the chain (as defined by EIP-155) in which the arbitrator application is running;
  • arbitratorJsonRpcUrl: string: the URL of JSON RPC endpoint connecting to a node on the network. It MUST be pointing to a node from the same chain identified by arbitratorChainID.
  • arbitrableContractAddress: string: the address of the arbitrable contract;
  • arbitrableChainID: number: the ID of the chain (as defined by EIP-155) in which the arbitrable application is running. If not provided by the Meta Evidence file, it SHOULD have the same value as arbitratorChainID.
  • arbitrableJsonRpcUrl: string: the URL of JSON RPC endpoint connecting to a node on the network. It MUST be pointing to a node from the same chain identified by arbitrableChainID.

Injecting parameters into dynamic scripts

From the original spec:

NOTE: Arbitrator interfaces should take security precautions when running an external script. A script should never be run directly inline as this would give the script full access to the DOM and make calls on behalf of the arbitrator. Instead the script should be run in a sandbox such as an iframe so that the scope is limited.

Arbitrator interfaces MUST include a read-only global variable named scriptParameters into the sandbox scope, which is an object containing the parameters listed above:

scriptParameters = {
  disputeID,
  arbitratorContractAddress,
  arbitratorChainID,
  arbitratorJsonRpcUrl,
  arbitrableContractAddress,
  arbitrableChainID,
  arbitratrableJsonRpcUrl,
};

Injecting parameters into evidence display interfaces

From the original spec:

NOTE: Arbitrator interfaces should take security precautions when injecting the evidence display interface code into their page. The iframe used to render the external interface should be secured properly with a sandbox or other means of disabling functionality that could pose a security risk to the interface or users. For example, an interface should disallow the injected web3 object from MetaMask or a different browser wallet from requesting signatures from the user. This can be accomplished by using a sandbox to disallow the external interface from retaining its origin (and therefore using the browser’s built in security features to block API requests), or by removing methods such as sign and personalSign from the injected web3 object.

Modern browsers already take care of most of the aspects pointed above. For example, a script from a page within an <iframe> is blocked from accessing the parent window global scope, which means trying to access window.ethereum from the Evidence Display Interface will not work.

The Arbitrator interface SHOULD inject the parameters into the Evidence Display Interface using standardized methods available. The most straightforward way of doing this is by appending a search part to evidenceDisplayInterfaceURI with all parameters properly encoded as URI components.

Supposing the evidenceDisplayURI value is https://my-awesome.display.app, when generating the src attribute of the <iframe> tag, it should become something like:

https://my-awesome.display.app/?
  arbitratorContractAddress=0x0000000000000000000000000000000000000000&
  disputeID=1&
  arbitratorChainID=1&
  arbitratorJsonRpcUrl=https%3A%2F%2Fmy-awesome.node.io&
  arbitrableContractAddress=0xC000000000000000000000000000000000000000&
  arbitratrableChainID=1&
  arbitratrableJsonRpcUrl=https%3A%2F%2Fmy-awesome.node.io&

To avoid issues with the encoding of the parameters, the Arbitrator interface SHOULD use proper APIs to generate the search part of the URL, such as URLSearchParams or encodeURIComponent.

Common Pitfalls

Hard-coded JSON RPC endpoints

Dynamic Scripts and Evidence Display Interfaces are meant to be immutable. If they include hard-coded parameters, such as the chain ID or the JSON RPC endpoint URL, it means that those cannot be patched in the future.

One clear example on how this falls short is when using RPC endpoints from Infura. They include an Infura project ID in them in order to identify the account responsible for it. Having an Infura endpoint is hard-coded into a dynamic script or an evidence display interface brings the following problems:

  1. The project ID is made public, since these components have to be publicly available.
  2. There is a hard limit in the amount of projects one can create on Infura. If there is ever a need for new projects, the only alternative is to remove old ones, which would break any dynamic script or evidence display interface depending on it.

Problem 2. above has further consequences:

  1. The Arbitrator application being permanently unable to display the right Evidence Display Interface or fetching the appropriate data with the Dynamic Script, which could lead to jurors refusing to rule on an otherwise valid case.
  2. For older cases, there would be a loss of historical data.

For that reason, neither dynamic script nor evidence display interfaces should rely on hard-coded parameters in order to connect to the blockchain.

Cross-chain/cross-rollup MetaEvidence

When defining MetaEvidence that will be on a chain that is different than the one where the Arbitrator is, the arbitrableChainID parameter MUST be hard-coded into it.

When injecting the parameters into dynamic scripts and evidence display interfaces, the Arbitrator interface SHOULD inject the proper JSON RPC endpoint for the respective aribtrableChainID.

The Arbitrator interface MUST be able to provide a valid JSON RPC endpoint for all chains it supports.

DateTime Ruling Option Type

Introducing a new type datetime for rulingOptions.type. Rulings will be signaled as UNIX timestamps.

Example:

Ruling code 1632930595 translates to Wed Sep 29 2021 15:49:55 GMT+0000.
Ruling code 1 translates to Thu Jan 01 1970 00:00:01 GMT+0000.

Reserved Rulings

To let arbitrable applications create reserved ruling options, we are introducing a new field rulingOptions.reserved. Values inside this object will be treated specially, the way it is defined in metaevidence.

Example:

 'rulingOptions': {
    ...
    'reserved': {
        '0x0': 'Invalid / Refuse to Arbitrate',
        '0x123454321': 'My Special Ruling Option'
    }
  }

Note that ruling code zero was always reserved for 'Invalid / Refuse to Arbitrate' implicitly, and it will stay that way. For sake of being explicit, you can include it inside metaevidence. User interfaces will ignore definitions for '0x0' anyway.

Reserved ruling options take precedence of regular ruling options. So for example, in a multiple-select dispute, if you define a ruling for code 0x4, using titles, and then you also define a reserved ruling on the same code, it will be overridden.

Example:

 'rulingOptions': {
    'type': 'multiple-select',
    'titles': ['Yes', 'No', 'Maybe', 'Perhaps'],
    'reserved': {
        '0x0': 'Invalid / Refuse to Arbitrate',
        '0x4': 'My Special Ruling Option'
    }
  }

'My Special Ruling Option' will override 'Perhaps' in the above configuration.

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

For that reason, neither dynamic script nor evidence display interfaces should rely on hard-coded parameters in order to connect to the blockchain.

Why add that parameter then? Shouldn't be the display interface's responsibility to connect to a JSON-RPC endpoint? It knows the chainId.

aliases
A mapping that can be used by the Arbitrator interface to translate each given key to the supplied value. For example, ETH addresses can be mapped to human readable terms to make the dispute easier to understand.

Maybe ENS is, at this point, a better standard for this, and this doesn't need to be addressed in the MetaEvidence.

If I was rate this EIP:

  • Overcomplication 10/10
  • YAGNI 10/10

Candid feedback on Kleros dev Slack: https://kleros.slack.com/archives/C65N18PT3/p1686340928234599

image

If I was rate this EIP:

  • Overcomplication 10/10
  • YAGNI 10/10

Candid feedback on Kleros dev Slack: https://kleros.slack.com/archives/C65N18PT3/p1686340928234599

image

Yes I agree some attributes are not easy to understand for people who are not in the Kleros space.

But (most of) the attributes are optional.

So I think we need to clarify the basic attributes versus advanced attributes.

Having slept on it - now I have second thoughts - I would like to apologise for disrespectful comment - in case it is understood the wrong way.

I still believe it is overcomplicated, I still believe it is YAGNI but every problem is an opportuity (positive thinking aspect)

More positive aspect:

image image

V2 coming so definitely worth to gather existing feedback and simplify, make it easier to integrate.

How do we ensure, whether it's for MetaEvidence or Evidence, that the evidence hasn't been altered if a (multi)hash isn't present in the URI i.e metaEvidenceID or evidence?

FYI

I posted on Kleros forum with a proposal to simplify the evidence standard: https://forum.kleros.io/t/the-simplest-evidence-standard-superseding-eip1497/954

I find this particular GitHub issue dated (most of the discussion from 2018 and 2019) but I'm not religious about it, as long as everyone is one the same page.


RANDOM RANT

I think I've just wasted 1 hour figuring things out, caching item.json in a database, doing some SQL join, in one place it was the ipfshash in some other /ipfs/ipfshash, what a bizarre of indicating the protocol, why not simply ipfs://ipfshash