github.com/klaytn/klaytn@v1.12.1/blockchain/system/registry.go (about) 1 // Copyright 2023 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package system 18 19 import ( 20 "context" 21 "math/big" 22 "sort" 23 24 "github.com/klaytn/klaytn/accounts/abi/bind" 25 "github.com/klaytn/klaytn/blockchain/state" 26 "github.com/klaytn/klaytn/common" 27 contracts "github.com/klaytn/klaytn/contracts/system_contracts" 28 "github.com/klaytn/klaytn/params" 29 ) 30 31 // Create storage state from the given initial values. 32 // The storage slots are calculated according to the solidity layout rule. 33 // https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html 34 func AllocRegistry(init *params.RegistryConfig) map[common.Hash]common.Hash { 35 if init == nil { 36 return nil 37 } 38 if init.Records == nil { 39 init.Records = make(map[string]common.Address) 40 } 41 storage := make(map[common.Hash]common.Hash) 42 43 // slot[0]: mapping(string => Record[]) records; 44 // In AllocRegistry, records[name] is always Record[] of one element. 45 // - records[x].length @ Hash(x, 0) 46 // - records[x][i].addr @ Hash(Hash(x, 0)) + (2*i) 47 // - records[x][i].activation @ Hash(Hash(x, 0)) + (2*i + 1) 48 for name, addr := range init.Records { 49 arraySlot := calcMappingSlot(0, name, 0) 50 storage[arraySlot] = lpad32(1) // records[name].length = 1 51 52 addrSlot := calcArraySlot(arraySlot, 2, 0, 0) 53 activationSlot := calcArraySlot(arraySlot, 2, 0, 1) 54 55 storage[addrSlot] = lpad32(addr) // records[name][0].addr 56 storage[activationSlot] = lpad32(0) // records[name][0].activation 57 } 58 59 names := make([]string, 0) 60 for name := range init.Records { 61 names = append(names, name) 62 } 63 sort.Strings(names) 64 65 // slot[1]: string[] names; 66 // - names.length @ 1 67 // - names[i] @ Hash(1) + i 68 storage[lpad32(1)] = lpad32(len(names)) 69 for i, name := range names { 70 nameSlot := calcArraySlot(1, 1, i, 0) // Hash(1) + 1*i + 0 71 for k, v := range allocDynamicData(nameSlot, []byte(name)) { 72 storage[k] = v 73 } 74 } 75 76 // slot[2]: address _owner; 77 storage[lpad32(2)] = lpad32(init.Owner) 78 79 return storage 80 } 81 82 func InstallRegistry(state *state.StateDB, init *params.RegistryConfig) error { 83 if err := state.SetCode(RegistryAddr, RegistryCode); err != nil { 84 return err 85 } 86 storage := AllocRegistry(init) 87 for key, value := range storage { 88 state.SetState(RegistryAddr, key, value) 89 } 90 return nil 91 } 92 93 func ReadActiveAddressFromRegistry(backend bind.ContractCaller, name string, num *big.Int) (common.Address, error) { 94 code, err := backend.CodeAt(context.Background(), RegistryAddr, num) 95 if err != nil { 96 return common.Address{}, err 97 } 98 if code == nil { 99 return common.Address{}, ErrRegistryNotInstalled 100 } 101 102 caller, err := contracts.NewRegistryCaller(RegistryAddr, backend) 103 if err != nil { 104 return common.Address{}, err 105 } 106 107 opts := &bind.CallOpts{BlockNumber: num} 108 return caller.GetActiveAddr(opts, name) 109 }