github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/contexts/shared.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/logging/structure" 13 "github.com/hyperledger/burrow/permission" 14 "github.com/hyperledger/burrow/txs/payload" 15 ) 16 17 type Context interface { 18 Execute(txe *exec.TxExecution, p payload.Payload) error 19 } 20 21 // The accounts from the TxInputs must either already have 22 // acm.PublicKey().(type) != nil, (it must be known), 23 // or it must be specified in the TxInput. If redeclared, 24 // the TxInput is modified and input.PublicKey() set to nil. 25 func getInputs(accountGetter acmstate.AccountGetter, ins []*payload.TxInput) (map[crypto.Address]*acm.Account, uint64, error) { 26 var total uint64 27 accounts := map[crypto.Address]*acm.Account{} 28 for _, in := range ins { 29 // Account shouldn't be duplicated 30 if _, ok := accounts[in.Address]; ok { 31 return nil, total, errors.Codes.DuplicateAddress 32 } 33 acc, err := accountGetter.GetAccount(in.Address) 34 if err != nil { 35 return nil, total, err 36 } 37 if acc == nil { 38 return nil, total, errors.Codes.InvalidAddress 39 } 40 accounts[in.Address] = acc 41 total += in.Amount 42 } 43 return accounts, total, nil 44 } 45 46 func getOrMakeOutputs(accountGetter acmstate.AccountGetter, accs map[crypto.Address]*acm.Account, 47 outs []*payload.TxOutput, logger *logging.Logger) (map[crypto.Address]*acm.Account, error) { 48 if accs == nil { 49 accs = make(map[crypto.Address]*acm.Account) 50 } 51 // we should err if an account is being created but the inputs don't have permission 52 var err error 53 for _, out := range outs { 54 accs[out.Address], err = getOrMakeOutput(accountGetter, accs, out.Address, logger) 55 if err != nil { 56 return nil, err 57 } 58 } 59 return accs, nil 60 } 61 62 func getOrMakeOutput(accountGetter acmstate.AccountGetter, accs map[crypto.Address]*acm.Account, 63 outputAddress crypto.Address, logger *logging.Logger) (*acm.Account, error) { 64 65 // Account shouldn't be duplicated 66 if _, ok := accs[outputAddress]; ok { 67 return nil, errors.Codes.DuplicateAddress 68 } 69 acc, err := accountGetter.GetAccount(outputAddress) 70 if err != nil { 71 return nil, err 72 } 73 // output account may be nil (new) 74 if acc == nil { 75 if !hasCreateAccountPermission(accountGetter, accs, logger) { 76 return nil, fmt.Errorf("at least one input does not have permission to create accounts") 77 } 78 logger.InfoMsg("Account not found so attempting to create it", "address", outputAddress) 79 acc = &acm.Account{ 80 Address: outputAddress, 81 Sequence: 0, 82 Balance: 0, 83 Permissions: permission.ZeroAccountPermissions, 84 } 85 } 86 87 return acc, nil 88 } 89 90 func validateOutputs(outs []*payload.TxOutput) (uint64, error) { 91 total := uint64(0) 92 for _, out := range outs { 93 // Good. Add amount to total 94 total += out.Amount 95 } 96 return total, nil 97 } 98 99 func adjustByInputs(accs map[crypto.Address]*acm.Account, ins []*payload.TxInput) error { 100 for _, in := range ins { 101 acc := accs[in.Address] 102 if acc == nil { 103 return fmt.Errorf("adjustByInputs() expects account in accounts, but account %s not found", in.Address) 104 } 105 if acc.Balance < in.Amount { 106 return fmt.Errorf("adjustByInputs() expects sufficient funds but account %s only has balance %v and "+ 107 "we are deducting %v", in.Address, acc.Balance, in.Amount) 108 } 109 err := acc.SubtractFromBalance(in.Amount) 110 if err != nil { 111 return err 112 } 113 } 114 return nil 115 } 116 117 func adjustByOutputs(accs map[crypto.Address]*acm.Account, outs []*payload.TxOutput) error { 118 for _, out := range outs { 119 acc := accs[out.Address] 120 if acc == nil { 121 return fmt.Errorf("adjustByOutputs() expects account in accounts, but account %s not found", 122 out.Address) 123 } 124 err := acc.AddToBalance(out.Amount) 125 if err != nil { 126 return err 127 } 128 } 129 return nil 130 } 131 132 //--------------------------------------------------------------- 133 134 // Get permission on an account or fall back to global value 135 func HasPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, perm permission.PermFlag, logger *logging.Logger) bool { 136 if perm > permission.AllPermFlags { 137 logger.InfoMsg( 138 fmt.Sprintf("HasPermission called on invalid permission 0b%b (invalid) > 0b%b (maximum) ", 139 perm, permission.AllPermFlags), 140 "invalid_permission", perm, 141 "maximum_permission", permission.AllPermFlags) 142 return false 143 } 144 145 globalPerms, err := acmstate.GlobalAccountPermissions(accountGetter) 146 if err != nil { 147 logger.TraceMsg("Error obtaining permission value (will default to false/deny)", 148 "perm_flag", perm.String(), 149 structure.ErrorKey, err) 150 return false 151 } 152 v, err := acc.Permissions.Base.Compose(globalPerms.Base).Get(perm) 153 if err != nil { 154 logger.TraceMsg("Error obtaining permission value (will default to false/deny)", 155 "perm_flag", perm.String(), 156 structure.ErrorKey, err) 157 return false 158 } 159 160 if v { 161 logger.TraceMsg("Account has permission", 162 "account_address", acc.GetAddress, 163 "perm_flag", perm.String()) 164 } else { 165 logger.TraceMsg("Account does not have permission", 166 "account_address", acc.GetAddress, 167 "perm_flag", perm.String()) 168 } 169 return v 170 } 171 172 func allHavePermission(accountGetter acmstate.AccountGetter, perm permission.PermFlag, 173 accs map[crypto.Address]*acm.Account, logger *logging.Logger) error { 174 for _, acc := range accs { 175 if !HasPermission(accountGetter, acc, perm, logger) { 176 return errors.PermissionDenied{ 177 Address: acc.Address, 178 Perm: perm, 179 } 180 } 181 } 182 return nil 183 } 184 185 func oneHasPermission(accountGetter acmstate.AccountGetter, perm permission.PermFlag, 186 accs map[crypto.Address]*acm.Account, logger *logging.Logger) error { 187 for _, acc := range accs { 188 if HasPermission(accountGetter, acc, perm, logger) { 189 return nil 190 } 191 } 192 return errors.PermissionDenied{ 193 Perm: perm, 194 } 195 } 196 197 func hasProposalPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 198 logger *logging.Logger) bool { 199 return HasPermission(accountGetter, acc, permission.Proposal, logger) 200 } 201 202 func hasInputPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 203 logger *logging.Logger) bool { 204 return HasPermission(accountGetter, acc, permission.Input, logger) 205 } 206 207 func hasBatchPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 208 logger *logging.Logger) bool { 209 return HasPermission(accountGetter, acc, permission.Batch, logger) 210 } 211 212 func hasNamePermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 213 logger *logging.Logger) bool { 214 return HasPermission(accountGetter, acc, permission.Name, logger) 215 } 216 217 func hasCallPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 218 logger *logging.Logger) bool { 219 return HasPermission(accountGetter, acc, permission.Call, logger) 220 } 221 222 func hasCreateContractPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 223 logger *logging.Logger) bool { 224 return HasPermission(accountGetter, acc, permission.CreateContract, logger) 225 } 226 227 func hasCreateAccountPermission(accountGetter acmstate.AccountGetter, accs map[crypto.Address]*acm.Account, 228 logger *logging.Logger) bool { 229 for _, acc := range accs { 230 if !HasPermission(accountGetter, acc, permission.CreateAccount, logger) { 231 return false 232 } 233 } 234 return true 235 } 236 237 func hasBondPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 238 logger *logging.Logger) bool { 239 return HasPermission(accountGetter, acc, permission.Bond, logger) 240 } 241 242 func hasBondOrSendPermission(accountGetter acmstate.AccountGetter, accs map[crypto.Address]*acm.Account, 243 logger *logging.Logger) bool { 244 for _, acc := range accs { 245 if !HasPermission(accountGetter, acc, permission.Bond, logger) { 246 if !HasPermission(accountGetter, acc, permission.Send, logger) { 247 return false 248 } 249 } 250 } 251 return true 252 }