cosmos源碼分析之五委託人delegators

一、委託人

在整個的cosmos中,委託人是一個非常重要的角色。通過委託機制可以達到全民參與的形式。這在EOS中也有體現。委託人,其實就是本身無力或者不想參與驗證過程的人,他們把自己的權益(代幣份額)交由某個人來代替執行自己的權益。
在整個的網絡中,驗證人的數量是有限的,正如美國大選,總統和議員總是少數,但是他們是由美國公民選舉出來的,可以把美國公民理解成委託人。當他們把票投給某個人時,某個人當選,然後當選的人就會有傾向性的做一些工作來回饋投票人。
在cosmos中,道理是相通的。

二、委託的流程

1、選擇驗證人
在委託前,還是要找一個利益最大化的驗證人來做爲自己的委託者。參照的信息包括:
驗證人的名稱、介紹、佣金變化率、最大佣金、最小抵押數量以及初始化佣金比例等。
2、委託人的說明

  • 1)委託人應該對驗證人進行仔細調查,因爲一理驗證人有問題,相應的委託人會跟隨的被懲罰。
  • 2)委託人在委託後也要積極監控驗證人,保證其合法進行工作,一旦有任何不滿意的地方,可以解綁並轉身另外一個驗證人。
  • 3)委託人可以通過投票權來制衡他們的驗證人。

3、收益
在前面提到過爲了抵抗通貨膨脹,會定期的增發Atom分配給抵押者。這就是一種收益,那麼收益有哪些方面呢?

  • 1)區塊增發的Atom獎勵。
  • 2)區塊獎勵(photon)。比如對硬分叉的投票表決時會有獎勵。
  • 3)交易費用,這個不用細說,幾乎所有的鏈都有這塊費用。

4、佣金
就如穩健型的投資一樣,每個驗證人的股權池會根據抵押比例獲取收益(利息)。不過,在將這筆收益按比例返給委託人時,驗證人有權抽取一筆佣金(手續費),換句話說,委託人想獲取收益,就必須向自己委託的驗證人提供一筆管理費。
這裏需要說明的是,佣金是委託人給予驗證人的。而收益是委託人拿到自己帳戶中的。
5、風險
把錢給別人用,這個風險是肯定有的。虛擬網絡和真實社會沒有什麼革命性的區別。那麼風險體現在哪兒呢?驗證人在行使權力的時候兒,Atom是被鎖倉的,首先沒辦法使用,再者,如果驗證人犯錯誤,Atom是要被罰減的。這裏面,就包含委託人的代幣。什麼原因會導致被處罰呢?

  • 1)重複簽名:如果釣魚者反饋一個驗證人在多條鏈上的相同高度上多次簽名,那麼就會被懲罰。
  • 2)不完成工作:也就是說不投票,佔着那個不那個。也會被懲罰。
  • 3)玩失蹤:這和2有些類似。

三、源碼

委託人和驗證人以及stake相關的部分中會有很強的關係。
stake.go

// delegation bond for a delegated proof of stake system
type Delegation interface {
	GetDelegator() Address // delegator address for the bond
	GetValidator() Address // validator owner address for the bond
	GetBondShares() Rat    // amount of validator's shares
}

// properties for the set of all delegations for a particular
type DelegationSet interface {

	// iterate through all delegations from one delegator by validator-address,
	//   execute func for each validator
	IterateDelegators(Context, delegator Address,
		fn func(index int64, delegation Delegation) (stop bool))
}

委託人的管理封裝數據結構。
delegation.go

// Delegation represents the bond with tokens held by an account.  It is
// owned by one delegator, and is associated with the voting power of one
// pubKey.
// TODO better way of managing space
type Delegation struct {
	DelegatorAddr sdk.Address `json:"delegator_addr"`
	ValidatorAddr sdk.Address `json:"validator_addr"`
	Shares        sdk.Rat     `json:"shares"`
	Height        int64       `json:"height"` // Last height bond updated
}

func (b Delegation) equal(b2 Delegation) bool {
	return bytes.Equal(b.DelegatorAddr, b2.DelegatorAddr) &&
		bytes.Equal(b.ValidatorAddr, b2.ValidatorAddr) &&
		b.Height == b2.Height &&
		b.Shares.Equal(b2.Shares)
}

// ensure fulfills the sdk validator types
var _ sdk.Delegation = Delegation{}

// nolint - for sdk.Delegation
func (b Delegation) GetDelegator() sdk.Address { return b.DelegatorAddr }
func (b Delegation) GetValidator() sdk.Address { return b.ValidatorAddr }
func (b Delegation) GetBondShares() sdk.Rat    { return b.Shares }

//Human Friendly pretty printer
func (b Delegation) HumanReadableString() (string, error) {
	bechAcc, err := sdk.Bech32ifyAcc(b.DelegatorAddr)
	if err != nil {
		return "", err
	}
	bechVal, err := sdk.Bech32ifyAcc(b.ValidatorAddr)
	if err != nil {
		return "", err
	}
	resp := "Delegation \n"
	resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
	resp += fmt.Sprintf("Validator: %s\n", bechVal)
	resp += fmt.Sprintf("Shares: %s", b.Shares.String())
	resp += fmt.Sprintf("Height: %d", b.Height)

	return resp, nil

}

這裏需要在處理的handle中控制綁定的委託者和驗證人
handler.go

// common functionality between handlers
func delegate(ctx sdk.Context, k Keeper, delegatorAddr sdk.Address,
	bondAmt sdk.Coin, validator Validator) (sdk.Tags, sdk.Error) {

	// Get or create the delegator bond
	bond, found := k.GetDelegation(ctx, delegatorAddr, validator.Owner)
	if !found {
		bond = Delegation{
			DelegatorAddr: delegatorAddr,
			ValidatorAddr: validator.Owner,
			Shares:        sdk.ZeroRat(),
		}
	}

	// Account new shares, save
	pool := k.GetPool(ctx)
	_, _, err := k.coinKeeper.SubtractCoins(ctx, bond.DelegatorAddr, sdk.Coins{bondAmt})
	if err != nil {
		return nil, err
	}
	validator, pool, newShares := validator.addTokensFromDel(pool, bondAmt.Amount)
	bond.Shares = bond.Shares.Add(newShares)

	// Update bond height
	bond.Height = ctx.BlockHeight()

	k.setPool(ctx, pool)
	k.setDelegation(ctx, bond)
	k.updateValidator(ctx, validator)
	tags := sdk.NewTags("action", []byte("delegate"), "delegator", delegatorAddr.Bytes(), "validator", validator.Owner.Bytes())
	return tags, nil
}

將委託者和驗證人綁定在一起是通過Msg的bond和unbond來實現的。

msg.go

// MsgDelegate - struct for bonding transactions
type MsgDelegate struct {
	DelegatorAddr sdk.Address `json:"delegator_addr"`
	ValidatorAddr sdk.Address `json:"validator_addr"`
	Bond          sdk.Coin    `json:"bond"`
}

func NewMsgDelegate(delegatorAddr, validatorAddr sdk.Address, bond sdk.Coin) MsgDelegate {
	return MsgDelegate{
		DelegatorAddr: delegatorAddr,
		ValidatorAddr: validatorAddr,
		Bond:          bond,
	}
}

// MsgUnbond - struct for unbonding transactions
type MsgUnbond struct {
	DelegatorAddr sdk.Address `json:"delegator_addr"`
	ValidatorAddr sdk.Address `json:"validator_addr"`
	Shares        string      `json:"shares"`
}

func NewMsgUnbond(delegatorAddr, validatorAddr sdk.Address, shares string) MsgUnbond {
	return MsgUnbond{
		DelegatorAddr: delegatorAddr,
		ValidatorAddr: validatorAddr,
		Shares:        shares,
	}
}

四、總結

通過上面的分析和說明,可以看出,委託人其實就是普通的網絡節點,驗證人的資格也不是你想有就有的。POS的機制決定了跟和資本主義社會一樣,沒有足夠的金錢,沒法參加大選。
這也是POS飽受詬病的地方,在COSMOS中也有一些防止的方法,但目前看來還不能從根本上解決問題。所以委託人在委託時,還是不要任性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章