github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/consensus/tribe/api.go (about) 1 package tribe 2 3 import ( 4 "context" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "math/big" 9 "time" 10 11 "github.com/SmartMeshFoundation/Spectrum/accounts" 12 "github.com/SmartMeshFoundation/Spectrum/accounts/keystore" 13 "github.com/SmartMeshFoundation/Spectrum/common" 14 "github.com/SmartMeshFoundation/Spectrum/crypto" 15 "github.com/SmartMeshFoundation/Spectrum/ethclient" 16 "github.com/SmartMeshFoundation/Spectrum/log" 17 "github.com/SmartMeshFoundation/Spectrum/params" 18 "github.com/SmartMeshFoundation/Spectrum/rpc" 19 ) 20 21 // fetchKeystore retrives the encrypted keystore from the account manager. 22 func fetchKeystore(am *accounts.Manager) *keystore.KeyStore { 23 return am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 24 } 25 26 func (api *API) BindSign(from *common.Address) (string, error) { 27 if from == nil { 28 return "", errors.New("args_can_not_empty") 29 } 30 nodekey := api.tribe.Status.getNodekey() 31 msg := crypto.Keccak256(from.Bytes()) 32 sig, err := crypto.Sign(msg, nodekey) 33 if err != nil { 34 return "", err 35 } 36 sigHex := hex.EncodeToString(sig) 37 return sigHex, nil 38 } 39 40 func (api *API) BindInfo(addr *common.Address, num *big.Int) (map[string]interface{}, error) { 41 if addr == nil { 42 nodekey := api.tribe.Status.getNodekey() 43 _addr := crypto.PubkeyToAddress(nodekey.PublicKey) 44 addr = &_addr 45 } 46 hash := api.chain.CurrentHeader().Hash() 47 if num != nil { 48 hash = api.chain.GetHeaderByNumber(num.Uint64()).Hash() 49 } 50 from, nodeids, err := params.AnmapBindInfo(*addr, hash) 51 if err != nil { 52 return nil, err 53 } 54 m := make(map[string]interface{}) 55 m["from"] = from 56 m["nodeids"] = nodeids 57 return m, nil 58 } 59 60 func (api *API) Bind(from *common.Address, passphrase string) (string, error) { 61 if from == nil { 62 return "", errors.New("args_can_not_empty") 63 } 64 a := accounts.Account{Address: *from} 65 e := fetchKeystore(api.accman).TimedUnlock(a, passphrase, 60*time.Second) 66 if e != nil { 67 return "", e 68 } 69 nodekey := api.tribe.Status.getNodekey() 70 nodeid := crypto.PubkeyToAddress(nodekey.PublicKey) 71 msg := crypto.Keccak256(from.Bytes()) 72 sig, err := crypto.Sign(msg, nodekey) 73 if err != nil { 74 return "", err 75 } 76 sigHex := hex.EncodeToString(sig) 77 tx, e := params.AnmapBind(*from, nodeid, sigHex) 78 if e != nil { 79 return "", e 80 } 81 log.Info("tribe.bind", "tx", tx, "from", from.Hex(), "nodeid", nodeid.Hex()) 82 return tx, nil 83 } 84 85 //PocDeposit 调用poc合约的deposit质押,满足金额以后,自动开启挖矿 86 func (api *API) PocDeposit(from *common.Address, passphrase string) (string, error) { 87 if from == nil { 88 return "", errors.New("args_can_not_empty") 89 } 90 a := accounts.Account{Address: *from} 91 e := fetchKeystore(api.accman).TimedUnlock(a, passphrase, 60*time.Second) 92 if e != nil { 93 return "", e 94 } 95 nodekey := api.tribe.Status.getNodekey() 96 nodeid := crypto.PubkeyToAddress(nodekey.PublicKey) 97 msg := crypto.Keccak256(from.Bytes()) 98 sig, err := crypto.Sign(msg, nodekey) 99 if err != nil { 100 return "", err 101 } 102 sigHex := hex.EncodeToString(sig) 103 tx, e := params.PocDeposit(*from, sigHex) 104 if e != nil { 105 return "", e 106 } 107 log.Info("tribe.pocDeposit", "tx", tx, "from", from.Hex(), "nodeid", nodeid.Hex()) 108 return tx, nil 109 } 110 111 //PocStart 调用poc合约的start,从stop状态恢复,开启挖矿 112 func (api *API) PocStart(from *common.Address, passphrase string) (string, error) { 113 return api.pocHelper(from, passphrase, params.POC_METHOD_START) 114 } 115 116 //PocStop 调用poc合约的stop,停止挖矿,准备撤回抵押 117 func (api *API) PocStop(from *common.Address, passphrase string) (string, error) { 118 return api.pocHelper(from, passphrase, params.POC_METHOD_STOP) 119 } 120 121 //PocWithdraw 调用poc合约的withdraw,在stop两周后,可以撤回押金 122 func (api *API) PocWithdraw(from *common.Address, passphrase string) (string, error) { 123 return api.pocHelper(from, passphrase, params.POC_METHOD_WITHDRAW) 124 } 125 126 //PocWithdrawSurplus 调用poc合约的PocWithdrawSurplus,从合约中撤回多余的抵押押金 127 func (api *API) PocWithdrawSurplus(from *common.Address, passphrase string) (string, error) { 128 return api.pocHelper(from, passphrase, params.POC_METHOD_WITHDRAW_SURPLUS) 129 } 130 func (api *API) pocHelper(from *common.Address, passphrase string, method string) (string, error) { 131 if from == nil { 132 return "", errors.New("args_can_not_empty") 133 } 134 var ( 135 tx string 136 e error 137 ) 138 a := accounts.Account{Address: *from} 139 e = fetchKeystore(api.accman).TimedUnlock(a, passphrase, 60*time.Second) 140 if e != nil { 141 return "", e 142 } 143 nodekey := api.tribe.Status.getNodekey() 144 nodeID := crypto.PubkeyToAddress(nodekey.PublicKey) 145 switch method { 146 case params.POC_METHOD_START: 147 tx, e = params.PocStart(*from, nodeID) 148 case params.POC_METHOD_STOP: 149 tx, e = params.PocStop(*from, nodeID) 150 case params.POC_METHOD_WITHDRAW: 151 tx, e = params.PocWithdraw(*from, nodeID) 152 case params.POC_METHOD_WITHDRAW_SURPLUS: 153 tx, e = params.PocWithdrawSurplus(*from, nodeID) 154 } 155 if e != nil { 156 return "", e 157 } 158 log.Info("tribe.", "method", method, "tx", tx, "from", from.Hex(), "nodeid", nodeID.Hex()) 159 return tx, nil 160 } 161 162 //PocGetStatus 查询poc合约状态 163 func (api *API) PocGetStatus(hash *common.Hash) (*params.PocStatus, error) { 164 header := api.chain.CurrentHeader() 165 h := header.Hash() 166 n := header.Number 167 if hash != nil { 168 h = *hash 169 h2 := api.chain.GetHeaderByHash(h) //有可能返回0值,当hash不存在的时候 170 if h2 == nil { 171 return nil, errors.New("block not exist") 172 } 173 n = h2.Number 174 } 175 return params.PocGetAll(h, n) 176 } 177 func (api *API) Unbind(from *common.Address, passphrase string) (string, error) { 178 nodekey := api.tribe.Status.getNodekey() 179 nodeid := crypto.PubkeyToAddress(nodekey.PublicKey) 180 if from == nil { 181 if m, err := api.BindInfo(&nodeid, nil); err != nil { 182 return "", err 183 } else { 184 _from := m["from"].(common.Address) 185 from = &_from 186 } 187 } 188 a := accounts.Account{Address: *from} 189 e := fetchKeystore(api.accman).TimedUnlock(a, passphrase, 60*time.Second) 190 if e != nil { 191 return "", e 192 } 193 msg := crypto.Keccak256(from.Bytes()) 194 sig, err := crypto.Sign(msg, nodekey) 195 if err != nil { 196 return "", err 197 } 198 sigHex := hex.EncodeToString(sig) 199 tx, e := params.AnmapUnbind(*from, nodeid, sigHex) 200 if e != nil { 201 return "", e 202 } 203 log.Info("tribe.unbind", "tx", tx, "from", from.Hex(), "nodeid", nodeid.Hex()) 204 return tx, nil 205 } 206 207 func (api *API) GetMiner(number *rpc.BlockNumber) (*TribeMiner, error) { 208 add := api.tribe.Status.GetMinerAddress() 209 ipcpath := params.GetIPCPath() 210 c, e := ethclient.Dial(ipcpath) 211 if e != nil { 212 return nil, e 213 } 214 ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) 215 defer cancel() 216 b, e := c.BalanceAt(ctx, add, nil) 217 if e != nil { 218 return nil, e 219 } 220 return &TribeMiner{add, b, api.tribe.Status.SignerLevel}, nil 221 } 222 223 // chief-0.0.3 show blacklist 224 func (api *API) GetSinners(hash *common.Hash) ([]common.Address, error) { 225 return api.tribe.Status.blackList, nil 226 } 227 228 func (api *API) GetSigners(hash *common.Hash) ([]*Signer, error) { 229 header := api.chain.CurrentHeader() 230 231 h := header.Hash() 232 n := header.Number 233 if hash != nil { 234 h = *hash 235 n = api.chain.GetHeaderByHash(h).Number 236 } 237 status, err := api.loadHistoryChiefStatus(h, n) 238 if err != nil { 239 return nil, err 240 } 241 return status.Signers, nil 242 } 243 244 func (api *API) GetStatus(hash *common.Hash) (*TribeStatus, error) { 245 header := api.chain.CurrentHeader() 246 h := header.Hash() 247 n := header.Number 248 if hash != nil { 249 h = *hash 250 h2 := api.chain.GetHeaderByHash(h) //有可能返回0值,当hash不存在的时候 251 if h2 == nil { 252 return nil, errors.New("block not exist") 253 } 254 n = h2.Number 255 } 256 return api.loadHistoryChiefStatus(h, n) 257 } 258 259 func (api *API) GetVolunteers(hash *common.Hash) (*TribeVolunteers, error) { 260 header := api.chain.CurrentHeader() 261 if hash != nil { 262 header = api.chain.GetHeaderByHash(*hash) 263 } else { 264 h := header.Hash() 265 hash = &h 266 } 267 rtn := params.SendToMsgBoxWithHash("GetVolunteers", *hash, header.Number) 268 r := <-rtn 269 if !r.Success { 270 return nil, r.Entity.(error) 271 } 272 cv := r.Entity.(params.ChiefVolunteers) 273 vs := &TribeVolunteers{cv.Length, make([]*Volunteer, 0, 0)} 274 if cv.Length != nil && cv.Length.Int64() > 0 { 275 for i, volunteer := range cv.VolunteerList { 276 weight := cv.WeightList[i] 277 vs.Volunteers = append(vs.Volunteers, &Volunteer{volunteer, weight.Int64()}) 278 } 279 } 280 return vs, nil 281 } 282 283 func (api *API) GetHistory(last *big.Int, noRpc *bool) (interface{}, error) { 284 s := uint64(16) 285 if last != nil { 286 s = last.Uint64() 287 } 288 cn := api.chain.CurrentHeader().Number.Uint64() 289 if noRpc != nil && *noRpc { 290 _history := make([]map[string]string, 0) 291 for i := cn; i > cn-s; i-- { 292 _header := api.chain.GetHeaderByNumber(i) 293 k := "🔨" 294 v := fmt.Sprintf("%d -> %s", _header.Number.Int64(), _header.Coinbase.Hex()) 295 if _header.Difficulty.Int64() == 1 { 296 k = "👿" 297 } 298 _h := map[string]string{k: v} 299 _history = append(_history, _h) 300 } 301 return _history, nil 302 } else { 303 _history := make([]History, 0) 304 for i := cn; i > cn-s; i-- { 305 _header := api.chain.GetHeaderByNumber(i) 306 _h := History{_header.Number.Int64(), _header.Hash(), _header.Coinbase, _header.Difficulty, _header.Time} 307 _history = append(_history[:], _h) 308 } 309 return _history, nil 310 } 311 } 312 313 // 在 加载完所有 node.service 后,需要主动调用一次 314 func (api *API) loadHistoryChiefStatus(hash common.Hash, number *big.Int) (status *TribeStatus, err error) { 315 //log.Info(fmt.Sprintf("LoadSignersFromChief hash=%s,number=%s", hash.String(), number)) 316 cs, err := params.TribeGetStatus(number, hash) 317 if err != nil { 318 return nil, err 319 } 320 status = &TribeStatus{} 321 signers := cs.SignerList 322 scores := cs.ScoreList 323 sl := make([]*Signer, 0, len(signers)) 324 for i, signer := range signers { 325 score := scores[i] 326 sl = append(sl, &Signer{signer, score.Int64()}) 327 } 328 status.LeaderLimit = cs.LeaderLimit 329 status.Leaders = cs.LeaderList 330 status.Number = cs.Number.Int64() 331 status.blackList = cs.BlackList 332 status.Signers = sl 333 status.Epoch, status.SignerLimit = cs.Epoch, cs.SignerLimit 334 chiefInfo := params.GetChiefInfo(number) 335 if chiefInfo != nil { 336 status.Vsn = chiefInfo.Version 337 } 338 api.setSignerLevel(hash, number, status) 339 return 340 } 341 342 func (api *API) setSignerLevel(hash common.Hash, number *big.Int, tmpStatus *TribeStatus) { 343 m := api.tribe.Status.GetMinerAddress() 344 for _, s := range tmpStatus.Signers { 345 if s.Address == m { 346 tmpStatus.SignerLevel = LevelSigner 347 return 348 } 349 } 350 for _, s := range tmpStatus.blackList { 351 if s == m { 352 tmpStatus.SignerLevel = LevelSinner 353 return 354 } 355 } 356 357 for _, s := range tmpStatus.Leaders { 358 if s == m { 359 tmpStatus.SignerLevel = LevelSigner 360 return 361 } 362 } 363 364 ci := params.GetChiefInfo(number) 365 switch ci.Version { 366 case "0.0.6": 367 // if filterVolunteer return 1 then is volunteer 368 rtn := params.SendToMsgBoxForFilterVolunteer(hash, number, m) 369 r := <-rtn 370 if r.Success { 371 if fr := r.Entity.(*big.Int); fr != nil && fr.Int64() == 0 { 372 tmpStatus.SignerLevel = LevelVolunteer 373 return 374 } 375 } 376 } 377 // default none 378 tmpStatus.SignerLevel = LevelNone 379 }