Smart Contract
Pb
A.08dd120226ec2213.Pb
1access(all) contract Pb {
2 /// only support Varint and LengthDelim for now
3 access(all) enum WireType: UInt8 {
4 access(all) case Varint
5 access(all) case Fixed64
6 access(all) case LengthDelim
7 access(all) case StartGroup
8 access(all) case EndGroup
9 access(all) case Fixed32
10 }
11
12 access(all) struct TagType {
13 access(all) let tag: UInt64
14 access(all) let wt: WireType
15 init(tag: UInt64, wt: UInt8){
16 self.tag = tag
17 self.wt = WireType(rawValue: wt)!
18 }
19 }
20
21 access(all) struct Buffer {
22 access(all) var idx: Int
23 access(all) let b: [UInt8] // readonly of original pb msg
24
25 init(raw: [UInt8]) {
26 self.idx = 0
27 self.b = raw
28 }
29 // if idx >= b.length, means we're done
30 access(all) view fun hasMore(): Bool {
31 return self.idx < self.b.length
32 }
33
34 // has to use struct as cadence can has only single return
35 access(all) fun decKey(): TagType {
36 let v = self.decVarint()
37 return TagType(tag: v/8, wt: UInt8(v % 8) )
38 }
39
40 // modify self.idx
41 access(all) fun decVarint(): UInt64 {
42 var ret: UInt64 = 0
43 // zero-copy for lower gas cost even though it may not matter
44 var i = 0
45 while i < 10 { // varint max 10 bytes
46 let b = self.b[self.idx+i]
47 ret = ret | UInt64(b & 0x7F) << UInt64(i * 7)
48 if (b < 0x80) {
49 self.idx = self.idx + i + 1;
50 return ret;
51 }
52 i = i + 1
53 }
54 assert(i<10, message: "invalid varint")
55 return ret
56 }
57 // modify self.idx
58 access(all) fun decBytes(): [UInt8] {
59 let len = self.decVarint()
60 let end = self.idx + Int(len)
61 assert(end <= self.b.length, message: "invalid bytes length: ".concat(end.toString()))
62 // array slice is https://github.com/onflow/cadence/pull/1315/files
63 // return self.b.slice(from: self.Idx, upTo: end)
64 var ret: [UInt8] = []
65 while self.idx < end {
66 ret.append(self.b[self.idx])
67 self.idx = self.idx + 1
68 }
69 return ret
70 }
71 }
72
73 // raw is UInt64 big endian, raw.length <= 8
74 access(all) fun toUInt64(_ raw: [UInt8]): UInt64 {
75 let rawLen = raw.length
76 assert(rawLen<=8, message: "invalid raw length for UInt64")
77 var ret: UInt64 = 0
78 var i = 0
79 while i < rawLen {
80 let val = UInt64(raw[rawLen - 1 - i]) << UInt64(i*8)
81 ret = ret + val
82 i = i + 1
83 }
84 return ret
85 }
86
87 // raw is UInt256 big endian, raw.length <= 32
88 access(all) fun toUInt256(_ raw: [UInt8]): UInt256 {
89 let rawLen = raw.length
90 assert(rawLen<=32, message: "invalid raw length for UInt256")
91 var ret: UInt256 = 0
92 var i = 0
93 while i < rawLen {
94 let val = UInt256(raw[rawLen - 1 - i]) << UInt256(i*8)
95 ret = ret + val
96 i = i + 1
97 }
98 return ret
99 }
100
101 access(all) fun toAddress(_ raw: [UInt8]): Address {
102 return Address(self.toUInt64(raw))
103 }
104
105 access(all) fun toUFix64(_ raw: [UInt8]): UFix64 {
106 let val = self.toUInt64(raw)
107 return UFix64(val/100_000_000) + UFix64(val % 100_000_000)/100_000_000.0
108 }
109
110 /// return hex string!
111 access(all) view fun toString(_ raw: [UInt8]): String {
112 return String.encodeHex(raw)
113 }
114}