Kindelia icon indicating copy to clipboard operation
Kindelia copied to clipboard

Cyclic functions are impossible because of arity check

Open racs4 opened this issue 2 years ago • 3 comments

Functions like (any cyclic set of functions)

A call B
B call C
C call A

Are currently impossible to do because of the arity check (which checks the arity of all calls in the function body)

As an example I have these three functions that add a node to a common binary search tree

fun (AddEq cond key t) {
  (AddEq #1 key {Node k v l r}) = {Node k (+ v #1) l r}
  (AddEq #0 key {Node k v l r}) = 
    dup k.0 k.1 = k;
    dup key.0 key.1 = key;
    (AddChild (> key.0 k.0) key.1 {Node k.1 v l r})
} = #0

fun (AddChild cond key t) {
  (AddChild #1 key {Node k v l r}) = {Node k v l (AddAcc key r)}
  (AddChild #0 key {Node k v l r}) = {Node k v (AddAcc key l) r}
} = #0

fun (AddAcc key t) {
  (AddAcc key {Node k v lft rgt}) =
    dup k.0 k.1 = k;
    dup key.0 key.1 = key;
    (AddEq (== k.0 key.0) key.1 {Node k.1 v lft rgt})
  (AddAcc key {Leaf}) = {Node key #1 {Leaf} {Leaf}}
} = #0

You can do this code in another way (I did it this way to avoid dups), I just want to know if this above shouldn't be possible

racs4 avatar Jun 09 '22 14:06 racs4

Fixed by removing the arity as a static test; it can be just performed at runtime. We must review the whole codebase to ensure nothing creates a term with an incorrect arity.

VictorTaelin avatar Jun 10 '22 14:06 VictorTaelin

We could allow mutual recursion and still avoid the runtime check with the static check if we define a way to compound/group statements. I think this is also important for other reasons, i.e. the time needed to deploy big programs in an attack-resistant way.

Btw, how do we reward miners for mining specific function deployments without grouping statements?

steinerkelvin avatar Jun 11 '22 20:06 steinerkelvin

What HVM-level compound statements add? This can be merely a feature of the node communication protocol.

Rewarding miners for deploying functions could be done with an IO.code name opcode.

fun Foo {
  ... stuff ...
}

fun Bar {
  ... stuff ...
}

run {
  !code foo_code 'Foo'
  !code bar_code 'Bar'
  if (& (= (Hash foo_code) FOO_HASH) (= (Hash bar_code) BAR_HASH) then
    !call ~ 'Kold' [{'Send' #100 block_miner}]
    !done #0
  else
    !done #0
}

VictorTaelin avatar Jun 12 '22 05:06 VictorTaelin