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  }