github.com/datachainlab/burrow@v0.25.0/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.ErrorCodeDuplicateAddress 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.ErrorCodeInvalidAddress 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.ErrorCodeDuplicateAddress 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 v, err := acc.Permissions.Base.Compose(acmstate.GlobalAccountPermissions(accountGetter).Base).Get(perm) 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 } 151 152 if v { 153 logger.TraceMsg("Account has permission", 154 "account_address", acc.GetAddress, 155 "perm_flag", perm.String()) 156 } else { 157 logger.TraceMsg("Account does not have permission", 158 "account_address", acc.GetAddress, 159 "perm_flag", perm.String()) 160 } 161 return v 162 } 163 164 func allHavePermission(accountGetter acmstate.AccountGetter, perm permission.PermFlag, 165 accs map[crypto.Address]*acm.Account, logger *logging.Logger) error { 166 for _, acc := range accs { 167 if !HasPermission(accountGetter, acc, perm, logger) { 168 return errors.PermissionDenied{ 169 Address: acc.Address, 170 Perm: perm, 171 } 172 } 173 } 174 return nil 175 } 176 177 func hasProposalPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 178 logger *logging.Logger) bool { 179 return HasPermission(accountGetter, acc, permission.Proposal, logger) 180 } 181 182 func hasInputPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 183 logger *logging.Logger) bool { 184 return HasPermission(accountGetter, acc, permission.Input, logger) 185 } 186 187 func hasBatchPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 188 logger *logging.Logger) bool { 189 return HasPermission(accountGetter, acc, permission.Batch, logger) 190 } 191 192 func hasNamePermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 193 logger *logging.Logger) bool { 194 return HasPermission(accountGetter, acc, permission.Name, logger) 195 } 196 197 func hasCallPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 198 logger *logging.Logger) bool { 199 return HasPermission(accountGetter, acc, permission.Call, logger) 200 } 201 202 func hasCreateContractPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 203 logger *logging.Logger) bool { 204 return HasPermission(accountGetter, acc, permission.CreateContract, logger) 205 } 206 207 func hasCreateAccountPermission(accountGetter acmstate.AccountGetter, accs map[crypto.Address]*acm.Account, 208 logger *logging.Logger) bool { 209 for _, acc := range accs { 210 if !HasPermission(accountGetter, acc, permission.CreateAccount, logger) { 211 return false 212 } 213 } 214 return true 215 } 216 217 func hasBondPermission(accountGetter acmstate.AccountGetter, acc *acm.Account, 218 logger *logging.Logger) bool { 219 return HasPermission(accountGetter, acc, permission.Bond, logger) 220 } 221 222 func hasBondOrSendPermission(accountGetter acmstate.AccountGetter, accs map[crypto.Address]*acm.Account, 223 logger *logging.Logger) bool { 224 for _, acc := range accs { 225 if !HasPermission(accountGetter, acc, permission.Bond, logger) { 226 if !HasPermission(accountGetter, acc, permission.Send, logger) { 227 return false 228 } 229 } 230 } 231 return true 232 }