github.com/klaytn/klaytn@v1.12.1/blockchain/system/kip113.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 "encoding/hex" 21 "encoding/json" 22 "math/big" 23 "sort" 24 "strings" 25 26 "github.com/klaytn/klaytn/accounts/abi/bind" 27 "github.com/klaytn/klaytn/common" 28 contracts "github.com/klaytn/klaytn/contracts/system_contracts" 29 "github.com/klaytn/klaytn/crypto/bls" 30 ) 31 32 type BlsPublicKeyInfo struct { 33 PublicKey []byte 34 Pop []byte 35 VerifyErr error // Nil if valid. Must check before use. 36 } 37 38 func newBlsPublicKeyInfo(publicKey []byte, pop []byte) BlsPublicKeyInfo { 39 return BlsPublicKeyInfo{ 40 PublicKey: publicKey, 41 Pop: pop, 42 VerifyErr: verifyBlsPublicKeyInfo(publicKey, pop), 43 } 44 } 45 46 func verifyBlsPublicKeyInfo(publicKey []byte, pop []byte) error { 47 pk, err := bls.PublicKeyFromBytes(publicKey) 48 if err != nil { 49 return err 50 } 51 52 sig, err := bls.SignatureFromBytes(pop) 53 if err != nil { 54 return err 55 } 56 57 if !bls.PopVerify(pk, sig) { 58 return ErrKip113BadPop 59 } 60 61 return nil 62 } 63 64 type BlsPublicKeyInfos map[common.Address]BlsPublicKeyInfo 65 66 func (infos BlsPublicKeyInfos) String() string { 67 obj := make(map[string]string) 68 for addr, info := range infos { 69 obj[addr.Hex()] = hex.EncodeToString(info.PublicKey) 70 } 71 j, _ := json.Marshal(obj) 72 return string(j) 73 } 74 75 type AllocKip113Init struct { 76 Infos BlsPublicKeyInfos 77 Owner common.Address 78 } 79 80 func AllocKip113Proxy(init AllocKip113Init) map[common.Hash]common.Hash { 81 if init.Infos == nil { 82 return nil 83 } 84 storage := make(map[common.Hash]common.Hash) 85 86 // Overall storage layout for KIP113 contract: 87 // 88 // | Name | Type | Slot | Offset | Bytes | 89 // |---------------|-----------------------------------------------------|------|--------|-------| 90 // | _initialized | uint8 | 0 | 0 | 1 | 91 // | _initializing | bool | 0 | 1 | 1 | 92 // | __gap | uint256[50] | 1 | 0 | 1600 | 93 // | __gap | uint256[50] | 51 | 0 | 1600 | 94 // | __gap | uint256[50] | 101 | 0 | 1600 | 95 // | _owner | address | 151 | 0 | 20 | 96 // | __gap | uint256[49] | 152 | 0 | 1568 | 97 // | allNodeIds | address[] | 201 | 0 | 32 | 98 // | record | mapping(address => struct IKIP113.BlsPublicKeyInfo) | 202 | 0 | 32 | 99 // 100 // We need to consider the following: 101 storage[lpad32(0)] = lpad32([]byte{0, 1}) // false, 1 102 storage[lpad32(151)] = lpad32(init.Owner) 103 104 addrs := make([]common.Address, 0) 105 for addr := range init.Infos { 106 addrs = append(addrs, addr) 107 } 108 sort.Slice(addrs, func(i, j int) bool { 109 return strings.Compare(addrs[i].Hex(), addrs[j].Hex()) > 0 110 }) 111 112 // slot[201]: address[] allNodeIds; 113 // - addrs.length @ 0 114 // - addrs[i] @ Hash(201) + i 115 storage[lpad32(201)] = lpad32(len(addrs)) 116 for i, addr := range addrs { 117 addrSlot := calcArraySlot(201, 1, i, 0) 118 storage[addrSlot] = lpad32(addr) 119 } 120 121 // slot[202]: mapping(address => BlsPublicKeyInfo) record; 122 // - infos[x].publicKey.length @ Hash(x, 202) = el 123 // - infos[x].publicKey @ Hash(el) + 0..1 124 // - infos[x].pop.length @ Hash(x, 202) + 1 = el 125 // - infos[x].pop @ Hash(el) + 0..2 126 for addr, info := range init.Infos { 127 // The below slot calculation assumes 48-byte and 96-byte Solidity `bytes` values. 128 if len(info.PublicKey) != 48 || len(info.Pop) != 96 { 129 logger.Crit("Invalid AllocKip113Init") 130 } 131 132 pubSlot := calcMappingSlot(202, addr, 0) 133 popSlot := calcMappingSlot(202, addr, 1) 134 135 for k, v := range allocDynamicData(pubSlot, info.PublicKey) { 136 storage[k] = v 137 } 138 for k, v := range allocDynamicData(popSlot, info.Pop) { 139 storage[k] = v 140 } 141 } 142 143 return storage 144 } 145 146 func AllocKip113Logic() map[common.Hash]common.Hash { 147 storage := make(map[common.Hash]common.Hash) 148 149 // We only need to case about _initialized, which is max(uint8). 150 storage[lpad32(0)] = lpad32([]byte{0xff}) 151 152 return storage 153 } 154 155 func ReadKip113All(backend bind.ContractCaller, contractAddr common.Address, num *big.Int) (BlsPublicKeyInfos, error) { 156 caller, err := contracts.NewIKIP113Caller(contractAddr, backend) 157 if err != nil { 158 return nil, err 159 } 160 161 opts := &bind.CallOpts{BlockNumber: num} 162 ret, err := caller.GetAllBlsInfo(opts) 163 if err != nil { 164 return nil, err 165 } 166 167 if len(ret.NodeIdList) != len(ret.PubkeyList) { 168 return nil, ErrKip113BadResult 169 } 170 171 infos := make(BlsPublicKeyInfos) 172 for i := 0; i < len(ret.NodeIdList); i++ { 173 addr := ret.NodeIdList[i] 174 infos[addr] = newBlsPublicKeyInfo( 175 ret.PubkeyList[i].PublicKey, 176 ret.PubkeyList[i].Pop, 177 ) 178 } 179 180 return infos, err 181 }