@@ -52,36 +52,60 @@ impl PlutusScripts {
52
52
#[ wasm_bindgen]
53
53
#[ derive( Clone , Debug , Eq , Ord , PartialEq , PartialOrd ) ]
54
54
pub struct ConstrPlutusData {
55
- tag : Int ,
55
+ alternative : BigNum ,
56
56
data : PlutusList ,
57
57
}
58
58
59
59
to_from_bytes ! ( ConstrPlutusData ) ;
60
60
61
61
#[ wasm_bindgen]
62
62
impl ConstrPlutusData {
63
- pub fn tag ( & self ) -> Int {
64
- self . tag . clone ( )
63
+ pub fn alternative ( & self ) -> BigNum {
64
+ self . alternative . clone ( )
65
65
}
66
66
67
67
pub fn data ( & self ) -> PlutusList {
68
68
self . data . clone ( )
69
69
}
70
70
71
- pub fn new ( tag : Int , data : & PlutusList ) -> Self {
71
+ pub fn new ( alternative : & BigNum , data : & PlutusList ) -> Self {
72
72
Self {
73
- tag ,
73
+ alternative : alternative . clone ( ) ,
74
74
data : data. clone ( ) ,
75
75
}
76
76
}
77
77
}
78
78
79
79
impl ConstrPlutusData {
80
- fn is_tag_compact ( tag : i128 ) -> bool {
81
- ( tag >= 121 && tag <= 127 ) || ( tag >= 1280 && tag <= 1400 )
80
+ // see: https://github.com/input-output-hk/plutus/blob/1f31e640e8a258185db01fa899da63f9018c0e85/plutus-core/plutus-core/src/PlutusCore/Data.hs#L61
81
+ // We don't directly serialize the alternative in the tag, instead the scheme is:
82
+ // - Alternatives 0-6 -> tags 121-127, followed by the arguments in a list
83
+ // - Alternatives 7-127 -> tags 1280-1400, followed by the arguments in a list
84
+ // - Any alternatives, including those that don't fit in the above -> tag 102 followed by a list containing
85
+ // an unsigned integer for the actual alternative, and then the arguments in a (nested!) list.
86
+ const GENERAL_FORM_TAG : u64 = 102 ;
87
+
88
+ // None -> needs general tag serialization, not compact
89
+ fn alternative_to_compact_cbor_tag ( alt : u64 ) -> Option < u64 > {
90
+ if alt <= 6 {
91
+ Some ( 121 + alt)
92
+ } else if alt >= 7 && alt <= 127 {
93
+ Some ( 1280 - 7 + alt)
94
+ } else {
95
+ None
96
+ }
82
97
}
83
98
84
- const GENERAL_FORM_TAG : u64 = 102 ;
99
+ // None -> General tag(=102) OR Invalid CBOR tag for this scheme
100
+ fn compact_cbor_tag_to_alternative ( cbor_tag : u64 ) -> Option < u64 > {
101
+ if cbor_tag >= 121 && cbor_tag <= 127 {
102
+ Some ( cbor_tag - 121 )
103
+ } else if cbor_tag >= 1280 && cbor_tag <= 1400 {
104
+ Some ( cbor_tag - 1280 + 7 )
105
+ } else {
106
+ None
107
+ }
108
+ }
85
109
}
86
110
87
111
const COST_MODEL_OP_COUNT : usize = 166 ;
@@ -606,15 +630,15 @@ impl Deserialize for PlutusScripts {
606
630
// TODO: write tests for this hand-coded implementation?
607
631
impl cbor_event:: se:: Serialize for ConstrPlutusData {
608
632
fn serialize < ' se , W : Write > ( & self , serializer : & ' se mut Serializer < W > ) -> cbor_event:: Result < & ' se mut Serializer < W > > {
609
- if Self :: is_tag_compact ( self . tag . 0 ) {
633
+ if let Some ( compact_tag ) = Self :: alternative_to_compact_cbor_tag ( from_bignum ( & self . alternative ) ) {
610
634
// compact form
611
- serializer. write_tag ( self . tag . 0 as u64 ) ?;
635
+ serializer. write_tag ( compact_tag as u64 ) ?;
612
636
self . data . serialize ( serializer)
613
637
} else {
614
638
// general form
615
639
serializer. write_tag ( Self :: GENERAL_FORM_TAG ) ?;
616
640
serializer. write_array ( cbor_event:: Len :: Len ( 2 ) ) ?;
617
- self . tag . serialize ( serializer) ?;
641
+ self . alternative . serialize ( serializer) ?;
618
642
self . data . serialize ( serializer)
619
643
}
620
644
}
@@ -623,13 +647,13 @@ impl cbor_event::se::Serialize for ConstrPlutusData {
623
647
impl Deserialize for ConstrPlutusData {
624
648
fn deserialize < R : BufRead + Seek > ( raw : & mut Deserializer < R > ) -> Result < Self , DeserializeError > {
625
649
( || -> Result < _ , DeserializeError > {
626
- let ( tag , data) = match raw. tag ( ) ? {
650
+ let ( alternative , data) = match raw. tag ( ) ? {
627
651
// general form
628
652
Self :: GENERAL_FORM_TAG => {
629
653
let len = raw. array ( ) ?;
630
654
let mut read_len = CBORReadLen :: new ( len) ;
631
655
read_len. read_elems ( 2 ) ?;
632
- let tag = Int :: deserialize ( raw) ?;
656
+ let alternative = BigNum :: deserialize ( raw) ?;
633
657
let data = ( || -> Result < _ , DeserializeError > {
634
658
Ok ( PlutusList :: deserialize ( raw) ?)
635
659
} ) ( ) . map_err ( |e| e. annotate ( "datas" ) ) ?;
@@ -640,17 +664,22 @@ impl Deserialize for ConstrPlutusData {
640
664
_ => return Err ( DeserializeFailure :: EndingBreakMissing . into ( ) ) ,
641
665
} ,
642
666
}
643
- ( tag , data)
667
+ ( alternative , data)
644
668
} ,
645
669
// concise form
646
- tag if Self :: is_tag_compact ( tag. into ( ) ) => ( Int :: new ( & to_bignum ( tag) ) , PlutusList :: deserialize ( raw) ?) ,
647
- invalid_tag => return Err ( DeserializeFailure :: TagMismatch {
648
- found : invalid_tag,
649
- expected : Self :: GENERAL_FORM_TAG ,
650
- } . into ( ) ) ,
670
+ tag => {
671
+ if let Some ( alternative) = Self :: compact_cbor_tag_to_alternative ( tag) {
672
+ ( to_bignum ( alternative) , PlutusList :: deserialize ( raw) ?)
673
+ } else {
674
+ return Err ( DeserializeFailure :: TagMismatch {
675
+ found : tag,
676
+ expected : Self :: GENERAL_FORM_TAG ,
677
+ } . into ( ) ) ;
678
+ }
679
+ } ,
651
680
} ;
652
681
Ok ( ConstrPlutusData {
653
- tag ,
682
+ alternative ,
654
683
data,
655
684
} )
656
685
} ) ( ) . map_err ( |e| e. annotate ( "ConstrPlutusData" ) )
@@ -1131,3 +1160,24 @@ impl Deserialize for Strings {
1131
1160
Ok ( Self ( arr) )
1132
1161
}
1133
1162
}
1163
+
1164
+ #[ cfg( test) ]
1165
+ mod tests {
1166
+ use super :: * ;
1167
+
1168
+ #[ test]
1169
+ pub fn plutus_constr_data ( ) {
1170
+ let constr_0 = PlutusData :: new_constr_plutus_data (
1171
+ & ConstrPlutusData :: new ( & to_bignum ( 0 ) , & PlutusList :: new ( ) )
1172
+ ) ;
1173
+ let constr_0_hash = hex:: encode ( hash_plutus_data ( & constr_0) . to_bytes ( ) ) ;
1174
+ assert_eq ! ( constr_0_hash, "923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec" ) ;
1175
+ let constr_0_roundtrip = PlutusData :: from_bytes ( constr_0. to_bytes ( ) ) . unwrap ( ) ;
1176
+ assert_eq ! ( constr_0, constr_0_roundtrip) ;
1177
+ let constr_1854 = PlutusData :: new_constr_plutus_data (
1178
+ & ConstrPlutusData :: new ( & to_bignum ( 1854 ) , & PlutusList :: new ( ) )
1179
+ ) ;
1180
+ let constr_1854_roundtrip = PlutusData :: from_bytes ( constr_1854. to_bytes ( ) ) . unwrap ( ) ;
1181
+ assert_eq ! ( constr_1854, constr_1854_roundtrip) ;
1182
+ }
1183
+ }
0 commit comments