github.com/datachainlab/burrow@v0.25.0/execution/contexts/permissions_context.go (about) 1 package contexts 2 3 import ( 4 "fmt" 5 6 "github.com/hyperledger/burrow/acm" 7 "github.com/hyperledger/burrow/acm/acmstate" 8 "github.com/hyperledger/burrow/crypto" 9 "github.com/hyperledger/burrow/execution/errors" 10 "github.com/hyperledger/burrow/execution/exec" 11 "github.com/hyperledger/burrow/logging" 12 "github.com/hyperledger/burrow/permission" 13 "github.com/hyperledger/burrow/txs/payload" 14 ) 15 16 type PermissionsContext struct { 17 StateWriter acmstate.ReaderWriter 18 Logger *logging.Logger 19 tx *payload.PermsTx 20 } 21 22 func (ctx *PermissionsContext) Execute(txe *exec.TxExecution, p payload.Payload) error { 23 var ok bool 24 ctx.tx, ok = p.(*payload.PermsTx) 25 if !ok { 26 return fmt.Errorf("payload must be PermsTx, but is: %v", txe.Envelope.Tx.Payload) 27 } 28 // Validate input 29 inAcc, err := ctx.StateWriter.GetAccount(ctx.tx.Input.Address) 30 if err != nil { 31 return err 32 } 33 if inAcc == nil { 34 ctx.Logger.InfoMsg("Cannot find input account", 35 "tx_input", ctx.tx.Input) 36 return errors.ErrorCodeInvalidAddress 37 } 38 39 err = ctx.tx.PermArgs.EnsureValid() 40 if err != nil { 41 return fmt.Errorf("PermsTx received containing invalid PermArgs: %v", err) 42 } 43 44 permFlag := ctx.tx.PermArgs.Action 45 // check permission 46 if !HasPermission(ctx.StateWriter, inAcc, permFlag, ctx.Logger) { 47 return fmt.Errorf("account %s does not have moderator permission %s (%b)", ctx.tx.Input.Address, 48 permFlag.String(), permFlag) 49 } 50 51 value := ctx.tx.Input.Amount 52 53 ctx.Logger.TraceMsg("New PermsTx", 54 "perm_args", ctx.tx.PermArgs.String()) 55 56 var permAcc *acm.Account 57 switch ctx.tx.PermArgs.Action { 58 case permission.HasBase: 59 // this one doesn't make sense from txs 60 return fmt.Errorf("HasBase is for contracts, not humans. Just look at the blockchain") 61 case permission.SetBase: 62 permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target, 63 func(perms *permission.AccountPermissions) error { 64 return perms.Base.Set(*ctx.tx.PermArgs.Permission, *ctx.tx.PermArgs.Value) 65 }) 66 case permission.UnsetBase: 67 permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target, 68 func(perms *permission.AccountPermissions) error { 69 return perms.Base.Unset(*ctx.tx.PermArgs.Permission) 70 }) 71 case permission.SetGlobal: 72 permAcc, err = mutatePermissions(ctx.StateWriter, acm.GlobalPermissionsAddress, 73 func(perms *permission.AccountPermissions) error { 74 return perms.Base.Set(*ctx.tx.PermArgs.Permission, *ctx.tx.PermArgs.Value) 75 }) 76 case permission.HasRole: 77 return fmt.Errorf("HasRole is for contracts, not humans. Just look at the blockchain") 78 case permission.AddRole: 79 permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target, 80 func(perms *permission.AccountPermissions) error { 81 if !perms.AddRole(*ctx.tx.PermArgs.Role) { 82 return fmt.Errorf("role (%s) already exists for account %s", 83 *ctx.tx.PermArgs.Role, *ctx.tx.PermArgs.Target) 84 } 85 return nil 86 }) 87 case permission.RemoveRole: 88 permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Target, 89 func(perms *permission.AccountPermissions) error { 90 if !perms.RemoveRole(*ctx.tx.PermArgs.Role) { 91 return fmt.Errorf("role (%s) does not exist for account %s", 92 *ctx.tx.PermArgs.Role, *ctx.tx.PermArgs.Target) 93 } 94 return nil 95 }) 96 default: 97 return fmt.Errorf("invalid permission function: %v", permFlag) 98 } 99 100 // TODO: maybe we want to take funds on error and allow txs in that don't do anythingi? 101 if err != nil { 102 return err 103 } 104 105 // Good! 106 inAcc.Balance -= value 107 err = inAcc.SubtractFromBalance(value) 108 if err != nil { 109 return errors.ErrorCodef(errors.ErrorCodeInsufficientFunds, 110 "Input account does not have sufficient balance to cover input amount: %v", ctx.tx.Input) 111 } 112 err = ctx.StateWriter.UpdateAccount(inAcc) 113 if err != nil { 114 return err 115 } 116 if permAcc != nil { 117 err = ctx.StateWriter.UpdateAccount(permAcc) 118 if err != nil { 119 return err 120 } 121 } 122 123 txe.Input(ctx.tx.Input.Address, nil) 124 txe.Permission(&ctx.tx.PermArgs) 125 return nil 126 } 127 128 func mutatePermissions(stateReader acmstate.Reader, address crypto.Address, 129 mutator func(*permission.AccountPermissions) error) (*acm.Account, error) { 130 131 account, err := stateReader.GetAccount(address) 132 if err != nil { 133 return nil, err 134 } 135 if account == nil { 136 return nil, fmt.Errorf("could not get account at address %s in order to alter permissions", address) 137 } 138 return account, mutator(&account.Permissions) 139 }