1
1
package data
2
2
3
3
import (
4
- "bytes"
5
4
"fmt"
6
5
"math/big"
7
6
@@ -33,8 +32,6 @@ func Decode(b []byte) (PlutusData, error) {
33
32
34
33
// cborUnmarshal acts like cbor.Unmarshal but allows us to set our own decoder options
35
34
func cborUnmarshal (dataBytes []byte , dest any ) error {
36
- data := bytes .NewReader (dataBytes )
37
- // Create a custom decoder that returns an error on unknown fields
38
35
decOptions := cbor.DecOptions {
39
36
// This defaults to 32, but there are blocks in the wild using >64 nested levels
40
37
MaxNestedLevels : 256 ,
@@ -43,8 +40,7 @@ func cborUnmarshal(dataBytes []byte, dest any) error {
43
40
if err != nil {
44
41
return err
45
42
}
46
- dec := decMode .NewDecoder (data )
47
- return dec .Decode (dest )
43
+ return decMode .Unmarshal (dataBytes , dest )
48
44
}
49
45
50
46
// decodeCborRaw is an alternative to cbor.Unmarshal() that converts cbor.Tag to Constr
@@ -103,21 +99,46 @@ func decodeCborRawList(data []byte) (any, error) {
103
99
}
104
100
105
101
func decodeCborRawMap (data []byte ) (any , error ) {
102
+ // The below is a hack to work around our CBOR library not supporting preserving key
103
+ // order when decoding a map. We decode our map to determine its length, create a dummy
104
+ // list the same length as our map to determine the header size, and then decode each
105
+ // key/value pair individually
106
106
var tmpData map [RawMessageStr ]RawMessageStr
107
107
if err := cborUnmarshal (data , & tmpData ); err != nil {
108
108
return nil , err
109
109
}
110
+ // Create dummy list of same length to determine map header length
111
+ tmpList := make ([]bool , len (tmpData ))
112
+ tmpListRaw , err := cborMarshal (tmpList )
113
+ if err != nil {
114
+ return nil , err
115
+ }
116
+ tmpListHeader := tmpListRaw [0 : len (tmpListRaw )- len (tmpData )]
117
+ // Strip off map header bytes
118
+ data = data [len (tmpListHeader ):]
110
119
pairs := make ([][2 ]PlutusData , 0 , len (tmpData ))
111
- for k , v := range tmpData {
112
- tmpKey , err := decodeCborRaw (k .Bytes ())
120
+ var rawKey , rawVal cbor.RawMessage
121
+ // Read key/value pairs until we have no data left
122
+ for len (data ) > 0 {
123
+ // Read raw key/value bytes
124
+ data , err = cbor .UnmarshalFirst (data , & rawKey )
125
+ if err != nil {
126
+ return nil , err
127
+ }
128
+ data , err = cbor .UnmarshalFirst (data , & rawVal )
129
+ if err != nil {
130
+ return nil , err
131
+ }
132
+ // Decode key/value
133
+ tmpKey , err := decodeCborRaw (rawKey )
113
134
if err != nil {
114
135
return nil , err
115
136
}
116
137
tmpKeyPd , err := decodeRaw (tmpKey )
117
138
if err != nil {
118
139
return nil , err
119
140
}
120
- tmpVal , err := decodeCborRaw (v . Bytes () )
141
+ tmpVal , err := decodeCborRaw (rawVal )
121
142
if err != nil {
122
143
return nil , err
123
144
}
0 commit comments