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

CIP-0039? | Language annotated address #310

Closed
wants to merge 3 commits into from
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions CIP-XXXX/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
CIP: XXXX
Title: Script language annotated addresses
Authors: Sebastien Guillemot <[email protected]>
Comments-URI: TBD
Status: Draft
Type: Standards
Created: 2022-07-29
License: CC-BY-4.0
---

# Abstract

Currently, scripts inside addresses are represented simply by their script hash with no indicated of which language was used to generate the script. This is problematic as it means users cannot know whether or not they are sending to a native script (very common use-case that is perfectly fine) or if they are sending to a Plutus script (in which case they may be accidentally locking their funds forever)

This proposal aims to solve tackle this issue by introducing a new address format that asserts the type of script held in its hash

# Motivation

Currently native scripts in Cardano are commonly used for multisig. Other proposals exist such as the [Arbitrary Script as Native Script spending conditions CIP](https://github.com/cardano-foundation/CIPs/pull/309) that enable native scripts to cover a larger set of use-cases as well. However, these multisig and proxy script users have trouble getting users to actually send ADA to them from their wallet. The reason why is that all wallets currently show a warning to the user if they are sending to a script address as there is no easy way for the wallet software to know whether or not a script is a native script or a native script
SebastienGllmt marked this conversation as resolved.
Show resolved Hide resolved

Additionally, this is not a problem that can easily be solved with better indexing tools for Cardano. This is because in the proxy native script contract use-case, it's possible that the proxy contract is unique for each individual user (some parameterized Plutus contract is calculated and then added as the requirement of the native script). Therefore, this feature benefits from being supported at the address level.

Lastly, the fact that addresses contain just their script hash without information about which language they use also leads to complexity in ledger rules and code of SDKs for Cardano as they cannot process any script language specific behavior until after the scripts are later provided as part of the witness. Knowing the language ahead of time allows the ledger to protect users from mistakes such as creating a Plutus V1 utxo entry with inline datum (which effectively makes it unspendable)
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't agree with this argument honestly. Disregarding the ledger complexity issue (which might be true), you will always make mistakes if you don't know the exact script in question. In what reasonable situation would you make a UTXO for a script address you don't know and then make the datum inline? I can not think of any.

What parts of the ledger could be simplified by adding this information? I'm not sure it's worth the decrease in efficiency due to increased transaction size.


# Specification

All addresses in Cardano currently start with a header that indicates which address type they are. Notably, these can be seen in [CIP19](../CIP-0019/README.md).

Note there are two ways we can support our modification to the address type:

1) Reserve a new address type as part of the header nibble. This is not great because it means we have to reserve many new address types (a new alternative for every case where the old address format contains a script hash)
2) Add a new column to existing address types that contain scripts. This doesn't work for pointer addresses because they are variable-width so it isn't possible to differentiate between the original address format and this annotated format (note that pointer addresses are almost never used on chain, so this is an acceptable limitation). This does, however, limit the kinds of modifications we could make to these address types in the future as we would need to make sure the length continues to uniquely identify the content.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yet more reasons to remove pointer addresses...


In this CIP, we propose using option (2) and extend the CIP19 table as follows:

Header type (`t t t t . . . .`) | script namespace* | Payment Part | script namespace* | Delegation Part
--- | --- | --- | --- |---
(0) `0000....` | ø | `PaymentKeyHash` | ø | `StakeKeyHash`
(1) `0001....` | 0-255 | `ScriptHash` | ø | `StakeKeyHash`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that the size of the namespace is not defined in the Cardano binary spec, so I just made it one byte. At the current rate (3 namespaces in 2 years since the Shelley release), we have enough for 84 years which seems decent.

If we wanted to optimize for address length, we have 3 optimization targets:

  1. Lowest amount of size on-chain (every bit counts). Probably we should avoid weird length addresses though
  2. Smallest hex representation (0xF vs 0xFF i.e. 0-16 vs 0-255). 16 seems way too small though
  3. Smallest bech32 representation (0-32 vs 0-1024 since bech32 takes 5 bit chunks). Using this also leads to weird length addresses though

(2) `0010....` | ø | `PaymentKeyHash` | 0-255 | `ScriptHash`
(3) `0011....` | 0-255 | `ScriptHash` | 0-255 | `ScriptHash`
(6) `0110....` | ø | `PaymentKeyHash` | ø | ø
(7) `0111....` | 0-255 | `ScriptHash` | ø | ø

**script namespace* is defined to be the key used to identify the script kind in the `script` of the [binary spec](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/babbage/test-suite/cddl-files/babbage.cddl#L421). Note that this is the same namespace used to generate a script hash from script bytes.

# Asserted language and script language mismatch

Note that nothing stops somebody from creating a mal-constructed address where the language asserted inside the address does not match the actual language used for the script hash.

This is an unlikely error since addresses are provided to the users by dApps. Additionally, even if due to an error the wrong address is used, funds are not permanently lost because the spending condition is still controlled by the script hash -- meaning they can still be spent and additionally can be considered
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you proposing that we do not validate the script namespace at the time of spending, when the scrip type becomes known? I worry about adding in a field that is not enforced. If folks cannot depend in the field being correct, it is dangerous to write code with that assumption (even if it normally hold true).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well the alternative is that if they get the namespace wrong then the funds are locked forever. Neither are great options

That being said, if we prefer to take neither option and avoid implementing this at the protocol level, having this supported as a user-level annotated address is still useful

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 prefer this to be checked.

Copy link
Contributor Author

@SebastienGllmt SebastienGllmt Aug 8, 2022

Choose a reason for hiding this comment

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

some thoughts for how to make these checked: make that any tx that sends to an annotated script address needs to provide the script in any of:

  1. The witness
  2. The auxiliary data
  3. An input (including reference inputs) that contains the inline script in its utxo entry

It makes using this feature a bit more expensive on-chain and a bit more tedious for wallets to implement, but allows having the correctness of the transaction be verifiable using the existing transaction context

Any other alternative to make this checked that includes something like "the full scrip for this hash has to appear somewhere on chain before" requires expanding the transaction validation context which may not be desirable.

Copy link
Contributor

Choose a reason for hiding this comment

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

To clarify, I think we could have any or all of the following kinds of checking:

  1. Checking upon spending such an output. This should be easy, since the witness is already there.
  2. Checking, locally, before creating such an output i.e. in cardano-api. This would require providing some extra information at transaction-creation time, but wouldn't bloat the transaction.
  3. Checking, on-chain, when creating such an output. This would require including the witness when creating the transaction, which is significantly more expensive and is a much bigger privacy leak since the preimage really would be publicly available on-chain before the output was spent.

I'm in favour of 1 (since it's cheap), optionally 2 (if they have the information, they might as well tell us for cross-checking), and probably not 3 (although I guess we could support it optionally?).


# On-chain vs off-chain encoding

There are two different ways this CIP can be implemented:

1. Purely as a wallet standard and, at the ledger rules level, the address format stays the same as before
2. Adding support for this new encoding in the ledger rules

The advantage of (1) is that it means this feature can be implemented without a hard fork. However, the disadvantage is that tools that parse chain history (wallets tx history on wallet restore, explorers, etc.) would not be able to show this new encoding for addresses potentially leading to user confusion (same address appearing in different formats at different places)

Therefore, although projects can implement this CIP before it is implemented on-chain, we still recommend adding support for this address encoding at the protocol level.

# Language vs script namespace

Care has to be taken when using the word `language` in Cardano. This is because strictly speaking, `language` is defined in the binary spec as any script type that has a cost model associated with it (i.e. PlutusV1 & PlutusV2. Does not include native scripts)
Copy link
Contributor

Choose a reason for hiding this comment

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

Our nomenclature is such a mess here :/


Since we explicitly want our CIP to be usable for native scripts, we instead use *script namespace* as defined above.