forked from ava-labs/avalanchego
-
Notifications
You must be signed in to change notification settings - Fork 4
/
add_delegator_tx.go
131 lines (110 loc) · 3.65 KB
/
add_delegator_tx.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package txs
import (
"errors"
"fmt"
"github.com/MetalBlockchain/metalgo/ids"
"github.com/MetalBlockchain/metalgo/snow"
"github.com/MetalBlockchain/metalgo/utils/constants"
"github.com/MetalBlockchain/metalgo/utils/crypto/bls"
"github.com/MetalBlockchain/metalgo/utils/math"
"github.com/MetalBlockchain/metalgo/vms/components/avax"
"github.com/MetalBlockchain/metalgo/vms/components/verify"
"github.com/MetalBlockchain/metalgo/vms/platformvm/fx"
"github.com/MetalBlockchain/metalgo/vms/secp256k1fx"
)
var (
_ DelegatorTx = (*AddDelegatorTx)(nil)
errDelegatorWeightMismatch = errors.New("delegator weight is not equal to total stake weight")
errStakeMustBeAVAX = errors.New("stake must be AVAX")
)
// AddDelegatorTx is an unsigned addDelegatorTx
type AddDelegatorTx struct {
// Metadata, inputs and outputs
BaseTx `serialize:"true"`
// Describes the delegatee
Validator `serialize:"true" json:"validator"`
// Where to send staked tokens when done validating
StakeOuts []*avax.TransferableOutput `serialize:"true" json:"stake"`
// Where to send staking rewards when done validating
DelegationRewardsOwner fx.Owner `serialize:"true" json:"rewardsOwner"`
}
// InitCtx sets the FxID fields in the inputs and outputs of this
// [UnsignedAddDelegatorTx]. Also sets the [ctx] to the given [vm.ctx] so that
// the addresses can be json marshalled into human readable format
func (tx *AddDelegatorTx) InitCtx(ctx *snow.Context) {
tx.BaseTx.InitCtx(ctx)
for _, out := range tx.StakeOuts {
out.FxID = secp256k1fx.ID
out.InitCtx(ctx)
}
tx.DelegationRewardsOwner.InitCtx(ctx)
}
func (*AddDelegatorTx) SubnetID() ids.ID {
return constants.PrimaryNetworkID
}
func (tx *AddDelegatorTx) NodeID() ids.NodeID {
return tx.Validator.NodeID
}
func (*AddDelegatorTx) PublicKey() (*bls.PublicKey, bool, error) {
return nil, false, nil
}
func (*AddDelegatorTx) PendingPriority() Priority {
return PrimaryNetworkDelegatorApricotPendingPriority
}
func (*AddDelegatorTx) CurrentPriority() Priority {
return PrimaryNetworkDelegatorCurrentPriority
}
func (tx *AddDelegatorTx) Stake() []*avax.TransferableOutput {
return tx.StakeOuts
}
func (tx *AddDelegatorTx) RewardsOwner() fx.Owner {
return tx.DelegationRewardsOwner
}
// SyntacticVerify returns nil iff [tx] is valid
func (tx *AddDelegatorTx) SyntacticVerify(ctx *snow.Context) error {
switch {
case tx == nil:
return ErrNilTx
case tx.SyntacticallyVerified: // already passed syntactic verification
return nil
}
if err := tx.BaseTx.SyntacticVerify(ctx); err != nil {
return err
}
if err := verify.All(&tx.Validator, tx.DelegationRewardsOwner); err != nil {
return fmt.Errorf("failed to verify validator or rewards owner: %w", err)
}
totalStakeWeight := uint64(0)
for _, out := range tx.StakeOuts {
if err := out.Verify(); err != nil {
return fmt.Errorf("output verification failed: %w", err)
}
newWeight, err := math.Add64(totalStakeWeight, out.Output().Amount())
if err != nil {
return err
}
totalStakeWeight = newWeight
assetID := out.AssetID()
if assetID != ctx.AVAXAssetID {
return fmt.Errorf("%w but is %q", errStakeMustBeAVAX, assetID)
}
}
switch {
case !avax.IsSortedTransferableOutputs(tx.StakeOuts, Codec):
return errOutputsNotSorted
case totalStakeWeight != tx.Wght:
return fmt.Errorf("%w, delegator weight %d total stake weight %d",
errDelegatorWeightMismatch,
tx.Wght,
totalStakeWeight,
)
}
// cache that this is valid
tx.SyntacticallyVerified = true
return nil
}
func (tx *AddDelegatorTx) Visit(visitor Visitor) error {
return visitor.AddDelegatorTx(tx)
}