Skip to content
This repository was archived by the owner on Jun 11, 2026. It is now read-only.

Commit 78ba394

Browse files
Merge pull request #53 from pragma-org/cip-153-value-type
Implements Value builtins and Value type
2 parents 82630a9 + 9e168e7 commit 78ba394

23 files changed

Lines changed: 1345 additions & 47 deletions

File tree

crates/uplc/src/builtin/default_function.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ pub enum DefaultFunction {
123123
// BLS Multi-Scalar Multiplication
124124
Bls12_381_G1_MultiScalarMul = 92,
125125
Bls12_381_G2_MultiScalarMul = 93,
126+
127+
// Value builtins
128+
InsertCoin = 94,
129+
LookupCoin = 95,
130+
UnionValue = 96,
131+
ValueContains = 97,
132+
ValueData = 98,
133+
UnValueData = 99,
134+
ScaleValue = 100,
126135
}
127136

128137
impl DefaultFunction {
@@ -222,6 +231,13 @@ impl DefaultFunction {
222231
DefaultFunction::IndexArray => 1,
223232
DefaultFunction::Bls12_381_G1_MultiScalarMul => 0,
224233
DefaultFunction::Bls12_381_G2_MultiScalarMul => 0,
234+
DefaultFunction::InsertCoin => 0,
235+
DefaultFunction::LookupCoin => 0,
236+
DefaultFunction::UnionValue => 0,
237+
DefaultFunction::ValueContains => 0,
238+
DefaultFunction::ValueData => 0,
239+
DefaultFunction::UnValueData => 0,
240+
DefaultFunction::ScaleValue => 0,
225241
}
226242
}
227243

@@ -321,6 +337,13 @@ impl DefaultFunction {
321337
DefaultFunction::IndexArray => 2,
322338
DefaultFunction::Bls12_381_G1_MultiScalarMul => 2,
323339
DefaultFunction::Bls12_381_G2_MultiScalarMul => 2,
340+
DefaultFunction::InsertCoin => 4,
341+
DefaultFunction::LookupCoin => 3,
342+
DefaultFunction::UnionValue => 2,
343+
DefaultFunction::ValueContains => 2,
344+
DefaultFunction::ValueData => 1,
345+
DefaultFunction::UnValueData => 1,
346+
DefaultFunction::ScaleValue => 2,
324347
}
325348
}
326349

@@ -441,30 +464,17 @@ impl DefaultFunction {
441464
| Ripemd_160
442465
);
443466

444-
// batch6: van Rossem (PV 11) — ExpModInteger, DropList, LengthOfArray, ListToArray,
445-
// IndexArray, BLS MSM, and Value builtins (once added).
446-
let batch6 = matches!(
447-
self,
448-
ExpModInteger
449-
| DropList
450-
| LengthOfArray
451-
| ListToArray
452-
| IndexArray
453-
| Bls12_381_G1_MultiScalarMul
454-
| Bls12_381_G2_MultiScalarMul
455-
);
456-
457467
match plutus_version {
458468
PlutusVersion::V1 => {
459469
if pv >= 11 {
460-
batch1 || batch2 || batch3 || batch4a || batch4b || batch5 || batch6
470+
true
461471
} else {
462472
batch1
463473
}
464474
}
465475
PlutusVersion::V2 => {
466476
if pv >= 11 {
467-
batch1 || batch2 || batch3 || batch4a || batch4b || batch5 || batch6
477+
true
468478
} else if pv >= 10 {
469479
batch1 || batch2 || batch3 || batch4b
470480
} else if pv >= 8 {
@@ -476,7 +486,7 @@ impl DefaultFunction {
476486
}
477487
PlutusVersion::V3 => {
478488
if pv >= 11 {
479-
batch1 || batch2 || batch3 || batch4a || batch4b || batch5 || batch6
489+
true
480490
} else if pv >= 10 {
481491
batch1 || batch2 || batch3 || batch4a || batch4b || batch5
482492
} else {

crates/uplc/src/constant.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{arena::Arena, binder::Eval, data::PlutusData, machine::MachineError, typ::Type};
1+
use crate::{
2+
arena::Arena, binder::Eval, data::PlutusData, ledger_value::LedgerValue, machine::MachineError,
3+
typ::Type,
4+
};
25

36
#[derive(Debug, PartialEq)]
47
pub enum Constant<'a> {
@@ -19,6 +22,7 @@ pub enum Constant<'a> {
1922
Bls12_381G1Element(&'a blst::blst_p1),
2023
Bls12_381G2Element(&'a blst::blst_p2),
2124
Bls12_381MlResult(&'a blst::blst_fp12),
25+
Value(&'a LedgerValue<'a>),
2226
}
2327

2428
pub type Integer = num::BigInt;
@@ -103,6 +107,10 @@ impl<'a> Constant<'a> {
103107
arena.alloc(Constant::Bls12_381MlResult(ml_res))
104108
}
105109

110+
pub fn ledger_value(arena: &'a Arena, v: &'a LedgerValue<'a>) -> &'a Constant<'a> {
111+
arena.alloc(Constant::Value(v))
112+
}
113+
106114
pub fn unwrap_data<V>(&'a self) -> Result<&'a PlutusData<'a>, MachineError<'a, V>>
107115
where
108116
V: Eval<'a>,
@@ -127,6 +135,7 @@ impl<'a> Constant<'a> {
127135
Constant::Bls12_381G1Element(_) => Type::g1(arena),
128136
Constant::Bls12_381G2Element(_) => Type::g2(arena),
129137
Constant::Bls12_381MlResult(_) => Type::ml_result(arena),
138+
Constant::Value(_) => Type::value(arena),
130139
}
131140
}
132141
}

crates/uplc/src/data.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,15 @@ impl<'a> PlutusData<'a> {
5454
arena: &'a Arena,
5555
cbor: &'_ [u8],
5656
) -> Result<&'a PlutusData<'a>, minicbor::decode::Error> {
57-
minicbor::decode_with(cbor, &mut Ctx { arena })
57+
minicbor::decode_with(
58+
cbor,
59+
&mut Ctx {
60+
arena,
61+
version: None,
62+
plutus_version: None,
63+
protocol_version: None,
64+
},
65+
)
5866
}
5967

6068
pub fn unwrap_constr<V>(

crates/uplc/src/flat/builtin.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,19 @@ pub fn try_from_tag(arena: &Arena, v: u8) -> Result<&DefaultFunction, FlatDecode
238238
Ok(arena.alloc(DefaultFunction::Bls12_381_G2_MultiScalarMul))
239239
}
240240

241+
// Value builtins
242+
v if v == DefaultFunction::InsertCoin as u8 => Ok(arena.alloc(DefaultFunction::InsertCoin)),
243+
v if v == DefaultFunction::LookupCoin as u8 => Ok(arena.alloc(DefaultFunction::LookupCoin)),
244+
v if v == DefaultFunction::UnionValue as u8 => Ok(arena.alloc(DefaultFunction::UnionValue)),
245+
v if v == DefaultFunction::ValueContains as u8 => {
246+
Ok(arena.alloc(DefaultFunction::ValueContains))
247+
}
248+
v if v == DefaultFunction::ValueData as u8 => Ok(arena.alloc(DefaultFunction::ValueData)),
249+
v if v == DefaultFunction::UnValueData as u8 => {
250+
Ok(arena.alloc(DefaultFunction::UnValueData))
251+
}
252+
v if v == DefaultFunction::ScaleValue as u8 => Ok(arena.alloc(DefaultFunction::ScaleValue)),
253+
241254
_ => Err(FlatDecodeError::DefaultFunctionNotFound(v)),
242255
}
243256
}

crates/uplc/src/flat/decode/decoder.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use bumpalo::collections::{String as BumpString, Vec as BumpVec};
22

3-
use crate::{arena::Arena, constant::Integer, flat::zigzag::ZigZag};
3+
use crate::{
4+
arena::Arena, builtin::DefaultFunction, constant::Integer, flat::zigzag::ZigZag,
5+
machine::PlutusVersion, program::Version,
6+
};
47

58
use super::FlatDecodeError;
69

@@ -12,6 +15,28 @@ pub struct Decoder<'b> {
1215

1316
pub struct Ctx<'a> {
1417
pub arena: &'a Arena,
18+
pub version: Option<&'a Version<'a>>,
19+
pub plutus_version: Option<PlutusVersion>,
20+
pub protocol_version: Option<u32>,
21+
}
22+
23+
impl<'a> Ctx<'a> {
24+
/// Returns true if gating is active and the program version is pre-1.1.0.
25+
pub fn program_is_pre_1_1_0(&self) -> bool {
26+
match self.version {
27+
Some(v) => v.is_less_than_1_1_0(),
28+
None => false,
29+
}
30+
}
31+
32+
/// Returns true if the given builtin is NOT available under the current
33+
/// plutus_version / protocol_version combination.
34+
pub fn is_builtin_gated(&self, func: &DefaultFunction) -> bool {
35+
match (self.plutus_version, self.protocol_version) {
36+
(Some(pv), Some(proto)) => !func.is_available_in(pv, proto),
37+
_ => false,
38+
}
39+
}
1540
}
1641

1742
impl<'b> Decoder<'b> {

crates/uplc/src/flat/decode/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ pub enum FlatDecodeError {
3636
TrailingBytes(usize),
3737
#[error("Builtin function {1} (tag {0}) is not available in the given language version")]
3838
BuiltinNotAvailable(u8, String),
39+
#[error("Constant type {1} (tag {0}) is not available before UPLC version 1.1.0")]
40+
ConstantTypeNotAvailable(u8, &'static str),
3941
}

0 commit comments

Comments
 (0)