github.com/mavryk-network/mvgo@v1.19.9/rpc/genesis.go (about) 1 // Copyright (c) 2020-2022 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 package rpc 5 6 import ( 7 "encoding/hex" 8 "encoding/json" 9 "fmt" 10 "strconv" 11 12 "github.com/echa/bson" 13 14 "github.com/mavryk-network/mvgo/mavryk" 15 "github.com/mavryk-network/mvgo/micheline" 16 ) 17 18 // lacking the algorithm to compute KT1 addresses from content, 19 // we hard-code all mainnet vesting KT1 addresses here 20 var vestingContractAddrs = []mavryk.Address{ 21 mavryk.MustParseAddress("KT1QuofAgnsWffHzLA7D78rxytJruGHDe7XG"), 22 mavryk.MustParseAddress("KT1CSKPf2jeLpMmrgKquN2bCjBTkAcAdRVDy"), 23 mavryk.MustParseAddress("KT1SLWhfqPtQq7f4zLomh8BNgDeprF9B6d2M"), 24 mavryk.MustParseAddress("KT1WPEis2WhAc2FciM2tZVn8qe6pCBe9HkDp"), 25 mavryk.MustParseAddress("KT1Um7ieBEytZtumecLqGeL56iY6BuWoBgio"), 26 mavryk.MustParseAddress("KT1Cz7TyVFvHxXpxLS57RFePrhTGisUpPhvD"), 27 mavryk.MustParseAddress("KT1Q1kfbvzteafLvnGz92DGvkdypXfTGfEA3"), 28 mavryk.MustParseAddress("KT1PDAELuX7CypUHinUgFgGFskKs7ytwh5Vw"), 29 mavryk.MustParseAddress("KT1A56dh8ivKNvLiLVkjYPyudmnY2Ti5Sba3"), 30 mavryk.MustParseAddress("KT1RUT25eGgo9KKWXfLhj1xYjghAY1iZ2don"), 31 mavryk.MustParseAddress("KT1FuFDZGdw86p6krdBUKoZfEMkcUmezqX5o"), 32 mavryk.MustParseAddress("KT1THsDNgHtN56ew9VVCAUWnqPC81pqAxCEp"), 33 mavryk.MustParseAddress("KT1EWLAQGPMF2uhtVRPaCH2vtFVN36Njdr6z"), 34 mavryk.MustParseAddress("KT1FN5fcNNcgieGjzxbVEPWUpJGwZEpzNGA8"), 35 mavryk.MustParseAddress("KT1TcAHw5gpejyemwRtdNyFKGBLc4qwA5gtw"), 36 mavryk.MustParseAddress("KT1VsSxSXUkgw6zkBGgUuDXXuJs9ToPqkrCg"), 37 mavryk.MustParseAddress("KT1Msatnmdy24sQt6knzpALs4tvHfSPPduA2"), 38 mavryk.MustParseAddress("KT1LZFMGrdnPjRLsCZ1aEDUAF5myA5Eo4rQe"), 39 mavryk.MustParseAddress("KT1LQ99RfGcmFe98PiBcGXuyjBkWzAcoXXhW"), 40 mavryk.MustParseAddress("KT1Kfbk3B6NYPCPohPBDU3Hxf5Xeyy9PdkNp"), 41 mavryk.MustParseAddress("KT1DnfT4hfikoMY3uiPE9mQV4y3Xweramb2k"), 42 mavryk.MustParseAddress("KT19xDbLsvQKnp9xqfDNPWJbKJJmV93dHDUa"), 43 mavryk.MustParseAddress("KT1HvwFnXteMbphi7mfPDhCWkZSDvXEz8iyv"), 44 mavryk.MustParseAddress("KT1KRyTaxCAM3YRquifEe29BDbUKNhJ6hdtx"), 45 mavryk.MustParseAddress("KT1Gow8VzXZx3Akn5kvjACqnjnyYBxQpzSKr"), 46 mavryk.MustParseAddress("KT1W148mcjmfvr9J2RvWcGHxsAFApq9mcfgT"), 47 mavryk.MustParseAddress("KT1D5NmtDtgCwPxYNb2ZK2But6dhNLs1T1bV"), 48 mavryk.MustParseAddress("KT1TzamC1SCj68ia2E4q2GWZeT24yRHvUZay"), 49 mavryk.MustParseAddress("KT1CM1g1o9RKDdtDKgcBWE59X2KgTc2TcYtC"), 50 mavryk.MustParseAddress("KT1FL3C6t9Lyfskyb6rQrCRQTnf7M9t587VM"), 51 mavryk.MustParseAddress("KT1JW6PwhfaEJu6U3ENsxUeja48AdtqSoekd"), 52 mavryk.MustParseAddress("KT1VvXEpeBpreAVpfp4V8ZujqWu2gVykwXBJ"), 53 } 54 55 type GenesisData struct { 56 Accounts []*X0 57 Contracts []*X1 58 Commitments []*X2 59 } 60 61 // bootstrap account with or without known public key 62 type X0 struct { 63 Addr mavryk.Address 64 Key mavryk.Key 65 Value int64 66 } 67 68 // bootstrap contract 69 type X1 struct { 70 Addr mavryk.Address 71 Delegate mavryk.Address 72 Value int64 73 Script micheline.Script 74 } 75 76 // commitment 77 type X2 struct { 78 Addr mavryk.Address 79 Value int64 80 } 81 82 func (b *GenesisData) Supply() int64 { 83 var s int64 84 for _, v := range b.Accounts { 85 s += v.Value 86 } 87 for _, v := range b.Contracts { 88 s += v.Value 89 } 90 for _, v := range b.Commitments { 91 s += v.Value 92 } 93 return s 94 } 95 96 func (b *GenesisData) UnmarshalText(data []byte) error { 97 buf := make([]byte, hex.DecodedLen(len(data))) 98 if _, err := hex.Decode(buf, data); err != nil { 99 return err 100 } 101 // decode BSON 102 encoded := &bootstrap{} 103 if err := bson.Unmarshal(buf[4:], encoded); err != nil { 104 return err 105 } 106 // convert BSON to Structs 107 acc, err := encoded.DecodeAccounts() 108 if err != nil { 109 return err 110 } 111 b.Accounts = acc 112 contracts, err := encoded.DecodeContracts() 113 if err != nil { 114 return err 115 } 116 b.Contracts = contracts 117 commit, err := encoded.DecodeCommitments() 118 if err != nil { 119 return err 120 } 121 b.Commitments = commit 122 return nil 123 } 124 125 // BSON data types 126 type bootstrap struct { 127 Accounts [][]string `bson:"bootstrap_accounts"` 128 Contracts []*contract `bson:"bootstrap_contracts"` 129 Commitments [][]string `bson:"commitments"` 130 } 131 132 type contract struct { 133 Delegate string `bson:"delegate"` 134 Value string `bson:"amount"` 135 Script bson.M `bson:"script"` 136 } 137 138 func (b *bootstrap) DecodeContracts() ([]*X1, error) { 139 // ignore non-mainnet contract lists (we don't know their addresses) 140 if len(b.Contracts) != len(vestingContractAddrs) { 141 return nil, nil 142 } 143 c := make([]*X1, len(b.Contracts)) 144 for i, v := range b.Contracts { 145 c[i] = &X1{ 146 Addr: vestingContractAddrs[i], 147 } 148 addr, err := mavryk.ParseAddress(v.Delegate) 149 if err != nil { 150 return nil, err 151 } 152 c[i].Delegate = addr 153 value, err := strconv.ParseInt(v.Value, 10, 64) 154 if err != nil { 155 return nil, err 156 } 157 c[i].Value = value 158 159 // script unmarshalling BSON -> JSON -> Micheline 160 buf, err := json.Marshal(v.Script) 161 if err != nil { 162 return nil, err 163 } 164 if err := json.Unmarshal(buf, &c[i].Script); err != nil { 165 return nil, err 166 } 167 168 // skip when this does not look like a vesting contract 169 isVesting := true 170 switch { 171 case !c[i].Script.Storage.IsValid(): 172 isVesting = false 173 case len(c[i].Script.Storage.Args) == 0: 174 isVesting = false 175 case !c[i].Script.Storage.Args[0].IsValid(): 176 isVesting = false 177 case len(c[i].Script.Storage.Args[0].Args) == 0: 178 isVesting = false 179 case !c[i].Script.Storage.Args[0].Args[1].IsValid(): 180 isVesting = false 181 case len(c[i].Script.Storage.Args[0].Args[1].Args) == 0: 182 isVesting = false 183 case !c[i].Script.Storage.Args[0].Args[1].Args[0].IsValid(): 184 isVesting = false 185 case len(c[i].Script.Storage.Args[0].Args[1].Args[0].Args) == 0: 186 isVesting = false 187 } 188 189 if !isVesting { 190 continue 191 } 192 193 // patch initial storage (convert strings to bytes) to circumvent tezos 194 // origination bug 195 // - replace edpk strings with byte sequences 196 // - replace delegate addesses with binary pkh 00 TT AAAA... 197 198 // keygroups >> signatories 199 for _, v := range c[i].Script.Storage.Args[0].Args[1].Args[0].Args { 200 for _, vv := range v.Args[0].Args { 201 edpk, err := mavryk.ParseKey(vv.String) 202 if err != nil { 203 return nil, fmt.Errorf("decoding signatory key %s: %v", vv.String, err) 204 } 205 vv.Type = micheline.PrimBytes 206 vv.Bytes = append([]byte{0}, edpk.Data...) 207 vv.String = "" 208 } 209 } 210 211 // only the first 8 contracts have authorizers set 212 if i < 8 { 213 // pour_dest 214 pair := c[i].Script.Storage.Args[1].Args[1].Args[0].Args 215 dest, err := mavryk.ParseAddress(pair[0].String) 216 if err != nil { 217 return nil, fmt.Errorf("decoding pour_dest %s: %v", pair[0].String, err) 218 } 219 pair[0].Type = micheline.PrimBytes 220 pair[0].Bytes = dest.Encode() 221 pair[0].String = "" 222 223 // pour_authorizer 224 edpk, err := mavryk.ParseKey(pair[1].String) 225 if err != nil { 226 return nil, fmt.Errorf("decoding pour_authorizer key %s: %v", pair[1].String, err) 227 } 228 // replace with byte sequence 229 pair[1].Type = micheline.PrimBytes 230 pair[1].Bytes = append([]byte{0}, edpk.Data...) 231 pair[1].String = "" 232 } 233 } 234 return c, nil 235 } 236 237 func (b *bootstrap) DecodeAccounts() ([]*X0, error) { 238 acc := make([]*X0, len(b.Accounts)) 239 for i, v := range b.Accounts { 240 acc[i] = &X0{} 241 pk := v[0] 242 switch { 243 case mavryk.HasKeyPrefix(pk): 244 key, err := mavryk.ParseKey(pk) 245 if err != nil { 246 return nil, err 247 } 248 acc[i].Key = key 249 acc[i].Addr = key.Address() 250 case mavryk.HasAddressPrefix(pk): 251 addr, err := mavryk.ParseAddress(pk) 252 if err != nil { 253 return nil, err 254 } 255 acc[i].Addr = addr 256 } 257 amount, err := strconv.ParseInt(v[1], 10, 64) 258 if err != nil { 259 return nil, err 260 } 261 acc[i].Value = amount 262 } 263 return acc, nil 264 } 265 266 func (b *bootstrap) DecodeCommitments() ([]*X2, error) { 267 c := make([]*X2, len(b.Commitments)) 268 for i, v := range b.Commitments { 269 c[i] = &X2{} 270 // [ $Blinded public key hash, $mumav ] 271 pk := v[0] 272 addr, err := mavryk.ParseAddress(pk) 273 if err != nil { 274 return nil, err 275 } 276 c[i].Addr = addr 277 amount, err := strconv.ParseInt(v[1], 10, 64) 278 if err != nil { 279 return nil, err 280 } 281 c[i].Value = amount 282 } 283 return c, nil 284 }