This repository has been archived by the owner on May 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 346
/
governance_context.go
152 lines (142 loc) · 4.37 KB
/
governance_context.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package contexts
import (
"fmt"
"math/big"
"github.com/hyperledger/burrow/acm"
"github.com/hyperledger/burrow/acm/acmstate"
"github.com/hyperledger/burrow/acm/validator"
"github.com/hyperledger/burrow/crypto"
"github.com/hyperledger/burrow/execution/errors"
"github.com/hyperledger/burrow/execution/exec"
"github.com/hyperledger/burrow/genesis/spec"
"github.com/hyperledger/burrow/logging"
"github.com/hyperledger/burrow/permission"
"github.com/hyperledger/burrow/txs/payload"
)
type GovernanceContext struct {
State acmstate.ReaderWriter
ValidatorSet validator.ReaderWriter
Logger *logging.Logger
tx *payload.GovTx
txe *exec.TxExecution
}
// GovTx provides a set of TemplateAccounts and GovernanceContext tries to alter the chain state to match the
// specification given
func (ctx *GovernanceContext) Execute(txe *exec.TxExecution, p payload.Payload) error {
var ok bool
ctx.txe = txe
ctx.tx, ok = p.(*payload.GovTx)
if !ok {
return fmt.Errorf("payload must be NameTx, but is: %v", txe.Envelope.Tx.Payload)
}
// Nothing down with any incoming funds at this point
accounts, _, err := getInputs(ctx.State, ctx.tx.Inputs)
if err != nil {
return err
}
// ensure all inputs have root permissions
err = allHavePermission(ctx.State, permission.Root, accounts, ctx.Logger)
if err != nil {
return errors.Wrap(err, "at least one input lacks permission for GovTx")
}
for _, i := range ctx.tx.Inputs {
txe.Input(i.Address, nil)
}
for _, update := range ctx.tx.AccountUpdates {
err := VerifyIdentity(ctx.State, update)
if err != nil {
return fmt.Errorf("GovTx: %v", err)
}
account, err := getOrMakeOutput(ctx.State, accounts, *update.Address, ctx.Logger)
if err != nil {
return err
}
governAccountEvent, err := ctx.UpdateAccount(account, update)
if err != nil {
txe.GovernAccount(governAccountEvent, errors.AsException(err))
return err
}
txe.GovernAccount(governAccountEvent, nil)
}
return nil
}
func (ctx *GovernanceContext) UpdateAccount(account *acm.Account, update *spec.TemplateAccount) (ev *exec.GovernAccountEvent, err error) {
ev = &exec.GovernAccountEvent{
AccountUpdate: update,
}
if update.Balances().HasNative() {
account.Balance = update.Balances().GetNative(0)
}
if update.Balances().HasPower() {
if update.PublicKey == nil {
err = fmt.Errorf("updateAccount should have PublicKey by this point but appears not to for "+
"template account: %v", update)
return
}
power := new(big.Int).SetUint64(update.Balances().GetPower(0))
_, err := ctx.ValidatorSet.SetPower(*update.PublicKey, power)
if err != nil {
return ev, err
}
}
if update.Code != nil {
account.EVMCode = *update.Code
if err != nil {
return ev, err
}
}
perms := account.Permissions
if len(update.Permissions) > 0 {
perms.Base, err = permission.BasePermissionsFromStringList(update.Permissions)
if err != nil {
return
}
}
if len(update.Roles) > 0 {
perms.Roles = update.Roles
}
account.Permissions = perms
if err != nil {
return
}
err = ctx.State.UpdateAccount(account)
return
}
func VerifyIdentity(sw acmstate.ReaderWriter, account *spec.TemplateAccount) (err error) {
if account.Address == nil && account.PublicKey == nil {
// We do not want to generate a key
return fmt.Errorf("could not execute Tx since account template %v contains neither "+
"address or public key", account)
}
if account.PublicKey == nil {
account.PublicKey, err = MaybeGetPublicKey(sw, *account.Address)
if err != nil {
return err
}
}
// Check address
if account.PublicKey != nil {
address := account.PublicKey.GetAddress()
if account.Address != nil && address != *account.Address {
return fmt.Errorf("supplied public key %v whose address %v does not match %v provided by"+
"GovTx", account.PublicKey, address, account.Address)
}
account.Address = &address
} else if account.Balances().HasPower() {
// If we are updating power we will need the key
return fmt.Errorf("must be provided with public key when updating validator power")
}
return nil
}
func MaybeGetPublicKey(sw acmstate.ReaderWriter, address crypto.Address) (*crypto.PublicKey, error) {
// First try state in case chain has received input previously
acc, err := sw.GetAccount(address)
if err != nil {
return nil, err
}
if acc != nil && acc.PublicKey.IsSet() {
publicKey := acc.PublicKey
return &publicKey, nil
}
return nil, nil
}