github.com/aergoio/aergo@v1.3.1/contract/name/name.go (about) 1 package name 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "strings" 7 8 "github.com/aergoio/aergo/state" 9 "github.com/aergoio/aergo/types" 10 ) 11 12 var prefix = []byte("name") 13 14 type NameMap struct { 15 Version byte 16 Owner []byte 17 Destination []byte 18 } 19 20 // AccountStateReader is an interface for getting a name account state. 21 type AccountStateReader interface { 22 GetNameAccountState() (*state.ContractState, error) 23 } 24 25 func CreateName(scs *state.ContractState, tx *types.TxBody, sender, receiver *state.V, name string) error { 26 amount := tx.GetAmountBigInt() 27 sender.SubBalance(amount) 28 receiver.AddBalance(amount) 29 return createName(scs, []byte(name), sender.ID()) 30 } 31 32 func createName(scs *state.ContractState, name []byte, owner []byte) error { 33 // return setAddress(scs, name, owner) 34 return registerOwner(scs, name, owner, owner) 35 } 36 37 //UpdateName is avaliable after bid implement 38 func UpdateName(bs *state.BlockState, scs *state.ContractState, tx *types.TxBody, 39 sender, receiver *state.V, name, to string) error { 40 amount := tx.GetAmountBigInt() 41 if len(getAddress(scs, []byte(name))) <= types.NameLength { 42 return fmt.Errorf("%s is not created yet", string(name)) 43 } 44 destination, _ := types.DecodeAddress(to) 45 destination = GetAddress(scs, destination) 46 sender.SubBalance(amount) 47 receiver.AddBalance(amount) 48 contract, err := bs.StateDB.OpenContractStateAccount(types.ToAccountID(destination)) 49 if err != nil { 50 return types.ErrTxInvalidRecipient 51 } 52 creator, err := contract.GetData([]byte("Creator")) 53 if err != nil { 54 return err 55 } 56 ownerAddr := destination 57 if creator != nil { 58 ownerAddr, err = types.DecodeAddress(string(creator)) 59 if err != nil { 60 return types.ErrTxInvalidRecipient 61 } 62 } 63 return updateName(scs, []byte(name), ownerAddr, destination) 64 } 65 66 func updateName(scs *state.ContractState, name []byte, owner []byte, to []byte) error { 67 //return setAddress(scs, name, to) 68 return registerOwner(scs, name, owner, to) 69 } 70 71 //Resolve is resolve name for chain 72 func Resolve(bs *state.BlockState, name []byte) []byte { 73 if len(name) == types.AddressLength || 74 strings.Contains(string(name), ".") { 75 return name 76 } 77 scs, err := openContract(bs) 78 if err != nil { 79 return name 80 } 81 return getAddress(scs, name) 82 } 83 84 func openContract(bs *state.BlockState) (*state.ContractState, error) { 85 v, err := bs.GetAccountStateV([]byte("aergo.name")) 86 if err != nil { 87 return nil, err 88 } 89 scs, err := bs.StateDB.OpenContractState(v.AccountID(), v.State()) 90 if err != nil { 91 return nil, err 92 } 93 return scs, nil 94 } 95 96 //GetAddress is resolve name for mempool 97 func GetAddress(scs *state.ContractState, name []byte) []byte { 98 if len(name) == types.AddressLength || 99 strings.Contains(string(name), ".") { 100 return name 101 } 102 return getAddress(scs, name) 103 } 104 105 func getAddress(scs *state.ContractState, name []byte) []byte { 106 nameMap := getNameMap(scs, name, true) 107 if nameMap != nil { 108 return nameMap.Destination 109 } 110 return nil 111 } 112 113 func GetOwner(scs *state.ContractState, name []byte) []byte { 114 return getOwner(scs, name, true) 115 } 116 117 func getOwner(scs *state.ContractState, name []byte, useInitial bool) []byte { 118 nameMap := getNameMap(scs, name, useInitial) 119 if nameMap != nil { 120 return nameMap.Owner 121 } 122 return nil 123 } 124 125 func getNameMap(scs *state.ContractState, name []byte, useInitial bool) *NameMap { 126 lowerCaseName := strings.ToLower(string(name)) 127 key := append(prefix, lowerCaseName...) 128 var err error 129 var ownerdata []byte 130 if useInitial { 131 ownerdata, err = scs.GetInitialData(key) 132 } else { 133 ownerdata, err = scs.GetData(key) 134 } 135 if err != nil { 136 return nil 137 } 138 return deserializeNameMap(ownerdata) 139 } 140 141 func GetNameInfo(r AccountStateReader, name string) (*types.NameInfo, error) { 142 scs, err := r.GetNameAccountState() 143 if err != nil { 144 return nil, err 145 } 146 owner := getOwner(scs, []byte(name), true) 147 return &types.NameInfo{Name: &types.Name{Name: string(name)}, Owner: owner, Destination: GetAddress(scs, []byte(name))}, err 148 } 149 150 func registerOwner(scs *state.ContractState, name, owner, destination []byte) error { 151 nameMap := &NameMap{Version: 1, Owner: owner, Destination: destination} 152 return setNameMap(scs, name, nameMap) 153 } 154 155 func setNameMap(scs *state.ContractState, name []byte, n *NameMap) error { 156 lowerCaseName := strings.ToLower(string(name)) 157 key := append(prefix, lowerCaseName...) 158 return scs.SetData(key, serializeNameMap(n)) 159 } 160 161 func serializeNameMap(n *NameMap) []byte { 162 var ret []byte 163 if n != nil { 164 ret = append(ret, n.Version) 165 buf := make([]byte, 8) 166 binary.LittleEndian.PutUint64(buf, uint64(len(n.Owner))) 167 ret = append(ret, buf...) 168 ret = append(ret, n.Owner...) 169 binary.LittleEndian.PutUint64(buf, uint64(len(n.Destination))) 170 ret = append(ret, buf...) 171 ret = append(ret, n.Destination...) 172 } 173 return ret 174 } 175 176 func deserializeNameMap(data []byte) *NameMap { 177 if data != nil { 178 version := data[0] 179 if version != 1 { 180 panic("could not deserializeOwner, not supported version") 181 } 182 offset := 1 183 next := offset + 8 184 sizeOfAddr := binary.LittleEndian.Uint64(data[offset:next]) 185 186 offset = next 187 next = offset + int(sizeOfAddr) 188 owner := data[offset:next] 189 190 offset = next 191 next = offset + 8 192 sizeOfDest := binary.LittleEndian.Uint64(data[offset:next]) 193 194 offset = next 195 next = offset + int(sizeOfDest) 196 destination := data[offset:next] 197 return &NameMap{ 198 Version: version, 199 Owner: owner, 200 Destination: destination, 201 } 202 } 203 return nil 204 }