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  }