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  }