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
/
permissions_context.go
131 lines (117 loc) · 4.05 KB
/
permissions_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
package contexts
import (
"fmt"
"github.com/hyperledger/burrow/acm"
"github.com/hyperledger/burrow/acm/acmstate"
"github.com/hyperledger/burrow/crypto"
"github.com/hyperledger/burrow/execution/errors"
"github.com/hyperledger/burrow/execution/exec"
"github.com/hyperledger/burrow/logging"
"github.com/hyperledger/burrow/permission"
"github.com/hyperledger/burrow/txs/payload"
)
type PermissionsContext struct {
StateWriter acmstate.ReaderWriter
Logger *logging.Logger
tx *payload.PermsTx
}
func (ctx *PermissionsContext) Execute(txe *exec.TxExecution, p payload.Payload) error {
var ok bool
ctx.tx, ok = p.(*payload.PermsTx)
if !ok {
return fmt.Errorf("payload must be PermsTx, but is: %v", txe.Envelope.Tx.Payload)
}
// Validate input
inAcc, err := ctx.StateWriter.GetAccount(ctx.tx.Input.Address)
if err != nil {
return err
}
if inAcc == nil {
ctx.Logger.InfoMsg("Cannot find input account",
"tx_input", ctx.tx.Input)
return errors.ErrorCodeInvalidAddress
}
err = ctx.tx.PermArgs.EnsureValid()
if err != nil {
return fmt.Errorf("PermsTx received containing invalid PermArgs: %v", err)
}
permFlag := ctx.tx.PermArgs.Action
// check permission
if !HasPermission(ctx.StateWriter, inAcc, permFlag, ctx.Logger) {
return fmt.Errorf("account %s does not have moderator permission %s (%b)", ctx.tx.Input.Address,
permFlag.String(), permFlag)
}
value := ctx.tx.Input.Amount
ctx.Logger.TraceMsg("New PermsTx",
"perm_args", ctx.tx.PermArgs.String())
var permAcc *acm.Account
switch ctx.tx.PermArgs.Action {
case permission.HasBase:
// this one doesn't make sense from txs
return fmt.Errorf("HasBase is for contracts, not humans. Just look at the blockchain")
case permission.SetBase:
permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target,
func(perms *permission.AccountPermissions) error {
return perms.Base.Set(*ctx.tx.PermArgs.Permission, *ctx.tx.PermArgs.Value)
})
case permission.UnsetBase:
permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target,
func(perms *permission.AccountPermissions) error {
return perms.Base.Unset(*ctx.tx.PermArgs.Permission)
})
case permission.SetGlobal:
permAcc, err = mutatePermissions(ctx.StateWriter, acm.GlobalPermissionsAddress,
func(perms *permission.AccountPermissions) error {
return perms.Base.Set(*ctx.tx.PermArgs.Permission, *ctx.tx.PermArgs.Value)
})
case permission.HasRole:
return fmt.Errorf("HasRole is for contracts, not humans. Just look at the blockchain")
case permission.AddRole:
permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target,
func(perms *permission.AccountPermissions) error {
if !perms.AddRole(*ctx.tx.PermArgs.Role) {
return fmt.Errorf("role (%s) already exists for account %s",
*ctx.tx.PermArgs.Role, *ctx.tx.PermArgs.Target)
}
return nil
})
case permission.RemoveRole:
permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target,
func(perms *permission.AccountPermissions) error {
if !perms.RemoveRole(*ctx.tx.PermArgs.Role) {
return fmt.Errorf("role (%s) does not exist for account %s",
*ctx.tx.PermArgs.Role, *ctx.tx.PermArgs.Target)
}
return nil
})
default:
return fmt.Errorf("invalid permission function: %v", permFlag)
}
// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
if err != nil {
return err
}
// Good!
inAcc.Balance -= value
if err != nil {
return err
}
ctx.StateWriter.UpdateAccount(inAcc)
if permAcc != nil {
ctx.StateWriter.UpdateAccount(permAcc)
}
txe.Input(ctx.tx.Input.Address, nil)
txe.Permission(&ctx.tx.PermArgs)
return nil
}
func mutatePermissions(stateReader acmstate.Reader, address crypto.Address,
mutator func(*permission.AccountPermissions) error) (*acm.Account, error) {
account, err := stateReader.GetAccount(address)
if err != nil {
return nil, err
}
if account == nil {
return nil, fmt.Errorf("could not get account at address %s in order to alter permissions", address)
}
return account, mutator(&account.Permissions)
}