Skip to content

Latest commit

 

History

History
159 lines (110 loc) · 17.2 KB

chip-0014.md

File metadata and controls

159 lines (110 loc) · 17.2 KB
CHIP Number 0014
Title New Chialisp ASSERT Conditions
Description Add new ASSERT conditions to Chialisp, and update mempool logic accordingly
Author Arvid Norberg
Editor Dan Perry
Comments-URI CHIPs repo, PR #59
Status Final
Category Standards Track
Sub-Category Chialisp
Created 2023-02-22
Requires None
Replaces None
Superseded-By None

Abstract

The Chialisp language currently includes conditions to assert that a block height or timestamp has been reached. This CHIP introduces the opposite conditions, which assert that a block height or timestamp has not been reached. It also includes conditions to assert that another spend occurs in the same block or spendbundle, as well as conditions to assert that the current coin was confirmed at a specified block height or timestamp, and a condition to ensure that a coin spend is ephemeral. Finally, this CHIP introduces new mempool logic that will eject a pending coin spend if that spend is no longer valid.

Motivation

Chialisp's current implementation contains four conditions that prevent a coin from being spent before a certain block height or timestamp:

Condition Format Valid if Compares against cmp
ASSERT_SECONDS_RELATIVE (80 seconds_passed) The current block's timestamp >= coin's birth timestamp + seconds_passed Current block >=
ASSERT_SECONDS_ABSOLUTE (81 seconds) The current block's timestamp >= seconds Current block >=
ASSERT_HEIGHT_RELATIVE (82 block_height_passed) The previous transaction block's height >= the coin's birth height + block_height_passed Previous transaction block >=
ASSERT_HEIGHT_ABSOLUTE (83 block_height) The previous transaction block's height >= block_height Previous transaction block >=

However, the opposite conditions do not exist. This CHIP presents a clean way to prevent a coin spend from being executed after a block height or timestamp.

The primary benefit of the conditions introduced in this CHIP is that they enable expiring Offers, which obviates the need for users to cancel their Offers manually, e.g. due to price slippage. The current coin spend would no longer be allowed after a certain block height or timestamp, and the mempool would reject this spend. A new spend of the same coin could later be created with a new set of conditions in the solution.

The CLVM already allows the condition codes from this proposal to be used, but there are currently no mappings thereof. These condition codes are therefore currently treated as no-ops, which always pass. The primary technical challenge of this CHIP is to add logic to the mempool to reject any coin spends that use expired conditions.

Backwards Compatibility

The new Chialisp conditions introduced in this CHIP are backwards compatible -- any calls that succeed after the CHIP has been implemented also would have been successful no-ops beforehand.

However, the Chialisp conditions to be added are not forward compatible -- before this CHIP has been implemented, the CLVM operators could have been called in an attempt to do something not specified in this CHIP. These calls would have been successful no-ops beforehand, but they will no longer succeed afterward.

Because of the forward incompatibility of the conditions to be added, this CHIP will require a soft fork of Chia's blockchain. As with all forks, there will be a risk of a chain split. The soft fork could also fail to be adopted. This might happen if an insufficient number of nodes have upgraded to include the changes introduced by this CHIP prior to the fork's block height.

Rationale

Our previous recommendation to enable expiring Offers was to create a singleton that uses the CREATE_COIN_ANNOUNCEMENT condition each time it is spent. Any coins that were to be involved in an expiring offer would then use the ASSERT_COIN_ANNOUNCEMENT condition to assert that the singleton was being spent in the same block. After the singleton was spent, the Offer coins would automatically be invalidated.

However, we have since realized that this technique is inadequate in cases where high frequency trading is desired because it would require a coin spend to make Offers expire. It is also an inelegant solution because it requires multiple coins to be spent simultaneously when an Offer is accepted.

The design laid out in this CHIP does not rely on any coin spends in order to invalidate an Offer. It also only requires a single coin to be spent in order for an Offer to be accepted.

Chia's standard transactions use a delegated puzzle, which allows the solver to specify the puzzle and solution they would like to run when the coin is spent, rather than when it is created. The new conditions introduced in this CHIP are recommended to be used in the solution for a delegated puzzle. In cases where the new conditions are no longer valid, the coins can still be spent with a new solution.

Specification

The soft fork will be activated at block 3 886 635. It will add the following conditions to Chialisp:

New conditions

Condition Format Valid if Compares against cmp
ASSERT_CONCURRENT_SPEND (64 coin_id) This coin is spent in the same block as the coin with the specified coin_id N/A =
ASSERT_CONCURRENT_PUZZLE (65 puzzle_hash) This coin is spent in the same block as at least one coin with the specified puzzle_hash N/A =
ASSERT_MY_BIRTH_SECONDS (74 seconds) This coin's birth timestamp is the same as seconds N/A =
ASSERT_MY_BIRTH_HEIGHT (75 block_height) This coin's birth height is the same as block_height N/A =
ASSERT_EPHEMERAL (76) This coin was created in the same block as it is being spent Current block =
ASSERT_BEFORE_SECONDS_RELATIVE (84 seconds_passed) The previous transaction block's timestamp is < this coin's birth timestamp + seconds_passed Previous transaction block <
ASSERT_BEFORE_SECONDS_ABSOLUTE (85 seconds) The previous transaction block's timestamp is < seconds Previous transaction block <
ASSERT_BEFORE_HEIGHT_RELATIVE (86 block_height_passed) The previous transaction block's height is < this coin's birth height + block_height_passed Previous transaction block <
ASSERT_BEFORE_HEIGHT_ABSOLUTE (87 block_height) The previous transaction block's height is < block_height Previous transaction block <

Modified conditions

In addition, this CHIP will modify two existing conditions. The current implementation (prior to this CHIP) has a discrepancy between the ASSERT_HEIGHT_* the ASSERT_SECONDS_* checks. The timestamp conditions compare against the current block and the height conditions compare against the previous transaction block.

Comparing against the previous transaction block was deliberate, to prevent the farmer from having an incentive to manipulate the timestamp of the new block. The comparison against the current block in the ASSERT_SECONDS_* conditions was unintentional.

The two conditions with this discrepancy are:

Current Condition Format Valid if Compares against cmp
ASSERT_SECONDS_RELATIVE (80 seconds_passed) The current block's timestamp >= coin's birth timestamp + seconds_passed Current block >=
ASSERT_SECONDS_ABSOLUTE (81 seconds) The current block's timestamp >= seconds Current block >=

This CHIP's soft fork will include the following update to the behavior of these conditions:

Updated Condition Format Valid if Compares against cmp
ASSERT_SECONDS_RELATIVE (80 seconds_passed) The previous block's timestamp >= coin's birth timestamp + seconds_passed Previous block >=
ASSERT_SECONDS_ABSOLUTE (81 seconds) The previous block's timestamp >= seconds Previous block >=

These changes come with an additional advantage -- by changing the behavior to rely on the previous block's time stamp, the incentive for farmers to pick an inaccurate timestamp for the current block is also removed when these conditions exist in the mempool.

Ephemeral coin spends

An ephemeral coin spend is a coin that is created and spent in the same block. The birth timestamp of a coin is the same as the timestamp of the block it was created in. The current implementation (prior to this CHIP) contains the following behaviors regarding ephemeral coin spends:

  • ASSERT_HEIGHT_RELATIVE 0 will fail because the previous transaction block's height is less than the current height plus zero.
  • ASSERT_SECONDS_RELATIVE 0 will succeed because the current block's time stamp is greater than or equal to the current block's timestamp plus zero.

If this CHIP is accepted:

  • ASSERT_HEIGHT_RELATIVE 0 will continue to fail; its functionality will not have changed.
  • ASSERT_SECONDS_RELATIVE 0 will fail because the previous block's time stamp is less than current block's timestamp plus zero.

Despite removing a farmer's incentive to modify a block's timestamp (as explained in the Modified conditions section), this incentive will still exist for ephemeral coin spends. This is because an ephemeral coin's birth timestamp is the same as the block's, and negative relative timestamp conditions could be used to depend on it. Because of this, two more changes will be made in this CHIP:

  • Disallow relative time lock conditions on ephemeral coin spends (this applies when the time lock values are negative). This will also ensure that the current implementation of treating a negative value as a no-op remains valid.
  • Add a new ASSERT_EPHEMERAL condition, which is listed in the New conditions section. This condition will require a coin to have been created in the same block as it is being spent. See also the note concerning this condition in the Security section.

Reference Implementation

The following pull requests have been merged to the Chia-Network/chia_rs GitHub repository as part of this CHIP:

  • 131 - add a new ENABLE_ASSERT_BEFORE flag to enable support for the new ASSERT conditions
  • 133 - add support for ASSERT_CONCURRENT_SPEND
  • 134 - add support for ASSERT_CONCURRENT_PUZZLE
  • 135 - add more checks for impossible constraints
  • 140 - Fix edge cases in parsing ASSERT_BEFORE_*
  • 144 - add support for ASSERT_MY_BIRTH_HEIGHT and ASSERT_MY_BIRTH_SECONDS
  • 149 - Add ASSERT_EPHEMERAL condition
  • 150 - assert not ephemeral (for relative timelocks)

The following pull requests have been merged to the Chia-Network/chia-blockchain GitHub repository as part of this CHIP:

  • 14625 - Softfork2 infrastructure
  • 14720 - ASSERT_MY_BIRTH_* conditions
  • 14733 - ASSERT_BEFORE_* conditions

Security

This CHIP comes with several security risks, all of which we feel are outweighed by the value added:

  1. Chia's blockchain may already contain unspent coins with puzzles that contain one or more of the conditions from this CHIP. Any such coins will need to be spent before the fork point is reached, or they will become permanently unspendable. However, we feel that the risk of this happening is low, for two reasons:

    • Before the fork point is reached, the conditions from this CHIP will be interpreted as no-ops, so they will always pass. Therefore, there is no reason for an existing coin to use any of these conditions, so it is unlikely that they exist.
    • If such a coin does exist, it will still be spendable until the fork point. Developers of these coins will be given ample warning to spend them.
  2. The mempool will require additional logic to remove any coin spends that are no longer valid. This means that the mempool will need to be re-calculated with each transaction block, thereby adding complexity. This new mempool logic will require extensive testing before it can be implemented on Chia's mainnet.

  3. The new Chialisp conditions could be used in a coin's puzzle, rather than in its solution as intended. Any coins with puzzles that contain one of these new conditions will need to be spent while the condition is still valid. If the condition becomes invalid, the coin will be rendered unspendable. This could happen for any number of unintended reasons, including:

    • If a coin will only be valid for one more block, a farmer could choose not to include that coin, thus permanently censoring it.
    • A coin spend must include a sufficient blockchain fee for inclusion. If the provided fee is insufficient, the coin could become unspendable if one of the conditions from the puzzle expires.
    • After a coin has been included in the blockchain, it could be removed in a re-org. In the case where a coin was spent on the final block where it remained valid, the re-org would then cause the coin to become unspendable.

    In addition, coins that use the conditions from this CHIP in their puzzles could be created such that they are always invalid. For example:

    • If the current block height is 100 and a coin is created with (ASSERT_BEFORE_HEIGHT_ABSOLUTE 100) in its puzzle, then at the time of the coin's creation, its last valid block height has already passed, so it will never be able to be spent.
    • If a coin is created with a puzzle that contains contradicting conditions, such as (ASSERT_BEFORE_HEIGHT_ABSOLUTE 100) and (ASSERT_HEIGHT_ABSOLUTE 100), then it can never be spent.

    Finally, if the ASSERT_EPHEMERAL condition is used in a coin's puzzle, rather than its solution, a farmer may choose to include the creation -- but not the ephemeral spend -- of the coin in the new block. The coin will never be considered ephemeral again, so the ASSERT_EPHEMERAL condition will fail for all future attempts to spend the coin. Thus, the farmer will have forced the coin to be bricked.

    In order to mitigate this risk, we will strongly recommend all Chialisp developers not to create any coins that include any of the conditions from this CHIP in their puzzles. The correct way to use these conditions is in the solution of a delegated puzzle. In this case, only the current spend of the coin could expire, but the coin itself would remain valid.

  4. A coin spend that has expired could become spendable in a re-org. This could lead to unintended consequences for anyone monitoring the blockchain to determine when the coin spend becomes invalid. However, because re-orgs are rare in Chia, this is unlikely to lead to any security issues.

Additional Assets

None

Copyright

Copyright and related rights waived via CC0.