aiken-lang / aiken

A modern smart contract platform for Cardano
https://aiken-lang.org
Apache License 2.0
454 stars 84 forks source link

Allow compiling targeting either PlutusV2 or PlutusV3 #907

Closed KtorZ closed 5 days ago

KtorZ commented 5 months ago

There are various places in the command-line and aiken-project crate which simply assume projects are expecting PlutusV2.

While supporting older version of Plutus indefinitely isn't considered useful (as one may simply ship smart contract with the latest version), there's a transitional period where supporting the latest and the previous one is necessary. If only for pioneers to try out new versions on testnets while others may stick to what is available on mainnet.

Thus, we should identify locations where the underlying Plutus version needs to be configurable and make it so. From the top of my head:

rvcas commented 5 months ago

this wasn't the plan. We agreed a while ago that we will flip the versions once V3 drops. People just need to wait. I'm not interested in making this configurable. Greater configurability means greater permutations of kinds of aiken projects in the wild. Once V3 is out there's not much reason to bother with V2 if you haven't even launched your contracts anyways. If you have well then you're stuck on V2 and code changes are a new script regardless so might as well accept V3. Anyone experimenting on sancho seems clever enough to make the small edits to have things work on V3 right now. Is it annoying? Yes but that is extremely temporary.

KtorZ commented 5 months ago

Is it annoying? Yes but that is extremely temporary.

This has been coming up a few times already though. So it seems like a sufficiently simple thing to allow -- even if only temporary. As said, I don't see much value in supporting V2 as soon as V3 is out. But making it easy for people to switch early to V3 is useful as it only makes the transition smoother for everyone.

The problem will occur again with V4, V5, and so on. So we better have a mechanism in place to deal with those transitional periods.

rvcas commented 5 months ago

ok no problem. I'm happy to have a changed position on the matter. Just wanted to double check if we cared to remain firm in our prior thinking.

rvcas commented 4 months ago

f it, we'll add a new field to the config called plutus version which will default to version 2 but can be set to 3. Any command that needs to care can simply read it out of the config.

jmagan commented 4 months ago

Hi!, since version 1.0.25 our repository https://github.com/Modulo-P/ak-381 isn't compiling. We're getting this error:

  × While trying to make sense of your code...
  ╰─▶ I found a type definition that has unsupported inhabitants.

    ╭─[/Users/juan.magan/ws/Modulo-P/ak-381/lib/ak-381/groth16.ak:33:1]
 33 │     pub fn pairing(g1: ByteArray, g2: ByteArray) {
 34 │ ╭─▶   bls12_381_miller_loop(
 35 │ │       bls12_381_g1_uncompress(g1),
 36 │ │       bls12_381_g2_uncompress(g2),
 37 │ ╰─▶   )
 38 │     }
    ╰────
  help: Data-types cannot contain values of type MillerLoopResult because they aren't serialisable into a Plutus Data. Yet this
        is necessary for inhabitants of compound structures like List, Tuple or Fuzzer.

I think it could be related to this issue. :)

KtorZ commented 4 months ago

@jmagan i don't think it is related. But the above error suggests that you are somewhere storing the MillerLoopResult in a list or a tuple? Or somehow casting it to Data? Could it be the case?

jmagan commented 4 months ago

I thought the same. This function is a helper function used only in the validator. I tried to remove the "pub" keyword and I tried also to put it inside the validator as an anonymous function but it didn't work either. I might be understanding something wrong.

pub fn groth_verify(
  vk: SnarkVerificationKey,
  proof: Proof,
  public: List<Int>,
) -> Bool {
  // let n = vk.nPublic
  let eAB = pairing(proof.piA, proof.piB)
  let eAlphaBeta = pairing(vk.vkAlpha, vk.vkBeta)

  let vkI =
    when vk.vkIC is {
      [] -> fail @"empty vkIC?"
      [head, ..tail] -> derive(tail, public, bls12_381_g1_uncompress(head))
    }

  let eIGamma = bls12_381_miller_loop(vkI, bls12_381_g2_uncompress(vk.vkGamma))
  let eCDelta = pairing(proof.piC, vk.vkDelta)

  // * Miller functions
  let mlr1 = bls12_381_mul_miller_loop_result(eAlphaBeta, eIGamma)
  let mlr2 = bls12_381_mul_miller_loop_result(mlr1, eCDelta)

  bls12_381_final_verify(eAB, mlr2)
}

AFAIK we aren't embedding this type on a list or tuple.

KtorZ commented 4 months ago

Could you try annotating the pairing function with a return type of ˋMillerLoopResult` (it's a type available in the Prelude, imported by default).

I am guessing that the type checker is trying to unify with 'Data' here for some reason.

jmagan commented 4 months ago

Yes, I did it and not working

KtorZ commented 1 month ago

Syntax and beginning of semantic suggestion for V3:

// V2 / Current Situation

validator(arg1: Whatever) {
  fn my_spend_function(datum: Datum, redeemer: Redeemer, ctx: ScriptContext) {
    expect Spend(utxo_ref) = ctx.purpose
    ...
  }

  fn my_mint_function(redeemer: Redeemer, ctx: ScriptContext) {
    expect Mint(policy_id) = ctx.purpose
    ...
  }
}

// V3 / Evolution
//
// + record-access syntax from the validator name.
// + else is optional, and desugarizes to "fail"
// + 'else fail' should parse, but be rewritten with curly braces because Aiken likes curly braces

validator my_validator(arg1: Whatever) {
  spend (datum: Option<Datum>, redeemer: Redeemer, utxo_ref: OutputReference, ctx: Transaction) {
    ...
  }

//  spend (datum: Datum, redeemer: Redeemer, utxo_ref: OutputReference, ctx: Transaction) {
//    ...
//  }
//
//  spend (redeemer: Redeemer, utxo_ref: OutputReference, ctx: Transaction) {
//    ...
//  }

  mint (redeemer: Redeemer, policy_id: PolicyId, ctx: Transaction) {
    ...
  }

  else(_) { fail }
}