chik-consensus

Utility functions and types used by the Chik blockchain full node

6 releases (breaking)

0.10.0 Jul 11, 2024
0.9.0 Jul 10, 2024
0.8.0 May 16, 2024
0.7.0 May 15, 2024
0.6.1 Apr 15, 2024

28 downloads per month
Used in 3 crates

Apache-2.0

750KB
18K SLoC

Implementation notes

Here are some edge cases that may be easy to get wrong in other implementations.

Interpreting integers

When interpreting atoms as integers in the conditions output from a SpendBundle, leading zeroes as well as sign-extending 0xff bytes are allowed.

As an optimization, all negative integers are either immediate failures (e.g. as a coin value) or turn the condition into a tautology (always true) (e.g. as a height or time condition). In the latter case, the whole condition can just be ignored.

This leaves valid, positive integers with leading zeroes. The integers in conditions are always limited to 32 or 64 bits, but given leading zeroes, the atoms can potentially be a lot larger than that. This opens up a denial of service challenge. It's non-trivial to make an implementation scan and ignore leading zeroes efficient enough to be viable against such attacks. Because of this the mempool will reject Spend Bundles returning conditions with any redundant leading zeroes. (Note that in order to make an integer positive, it's sometimes necessary to have a single leading zero. That wouldn't count as redundant).

This implementation of condition parsing and checking is robust enough to withstand this attack, which currently can only be launched by a farmer (since the mempool rejects it for non-farmers).

Relative height condition of 0

Similar to how some conditions with negative arguments are tautologies, so are some conditions with a 0 argument. E.g. ASSERT_SECONDS_RELATIVE ASSERT_SECONDS_ABSOLUTE ASSERT_HEIGHT_ABSOLUTE.

Notably absent from this list is ASSERT_HEIGHT_RELATIVE. A relative height condition of 0 still prevents spending the coin in the same block (as an ephemeral coin). The ASSERT_HEIGHT_RELATIVE condition requires that the height difference between the creation of the coin and spending it exceeds the parameter (0 in this case).

This is a bit of an inconsistency, since ASSERT_SECONDS_RELATIVE of 0 does allow spending the coin in the same block. All spends in a block happen simultaneously, so the time difference between the spends doesn't exceed 0, it is 0.

List NIL terminators

The output from a Spend Bundle or block generator program is expected to be:

(
  (
    (*parent-coin-id* *puzzle-hash* *amount*   # <- identify the coin to be spent
      (
        (
          (*condition-code* *condition-args...*)  # <- first condition
          ... # more conditions here. Must have valid terminator
        )
        *future-extensions*
      )
    )
    ... # more spends here, must have valid terminator
  )
   *future-extensions*
)

Some of these lists must be terminated by a NIL atom, whereas others are parsed forgivingly, just requiring the list to end with any atom on the right hand side.

Lists requiring NIL termination:

  1. The list of Spends (i.e. identifying a coin to be spent along with the conditions)
  2. The list of conditions

Lists not requiring NIL termination:

  1. The outer list of spends, that's there to allow for future extensions
  2. The outer list of conditions, there to allow for future extensions
  3. The list of condition arguments

A NIL terminator is an atom of length 0, used as the right-hand element at the end of the list.

(A . (B . (C . ())))

A list that does not require a NIL terminator can end with any kind of atom. E.g.

(A . (B . (C . 8)))

Additional arguments to conditions

Additional arguments are allowed to conditions, and ignored. This is to leave room for future expansion. One exception is the AGG_SIG_UNSAFE and AGG_SIG_ME conditions. They both require exactly 2 arguments. Anything else is a condition failure.

Deduplicating identical spends

The feature that deduplicates identical spends, in the mempool, can only work with spends that do not have any AGG_SIG_ME nor AGG_SIG_UNSAFE conditions. Because the signature cannot be subtracted from the aggregated siggnature in the general case. This feature is only active when these conditions are met:

  • The spend does not output an AGG_SIG_ME nor an AGG_SIG_UNSAFE condition.
  • The spend uses the exact same solution.

Spends that are eligible for deduplication are marked with a bool in the Spend object when running the generator.

Dependencies

~10–17MB
~309K SLoC