github.com/datachainlab/burrow@v0.25.0/execution/contexts/send_context.go (about)

     1  package contexts
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hyperledger/burrow/acm/acmstate"
     7  	"github.com/hyperledger/burrow/execution/errors"
     8  	"github.com/hyperledger/burrow/execution/exec"
     9  	"github.com/hyperledger/burrow/logging"
    10  	"github.com/hyperledger/burrow/permission"
    11  	"github.com/hyperledger/burrow/txs/payload"
    12  )
    13  
    14  type SendContext struct {
    15  	StateWriter acmstate.ReaderWriter
    16  	Logger      *logging.Logger
    17  	tx          *payload.SendTx
    18  }
    19  
    20  func (ctx *SendContext) Execute(txe *exec.TxExecution, p payload.Payload) error {
    21  	var ok bool
    22  	ctx.tx, ok = p.(*payload.SendTx)
    23  	if !ok {
    24  		return fmt.Errorf("payload must be NameTx, but is: %v", txe.Envelope.Tx.Payload)
    25  	}
    26  	accounts, inTotal, err := getInputs(ctx.StateWriter, ctx.tx.Inputs)
    27  	if err != nil {
    28  		return err
    29  	}
    30  
    31  	// ensure all inputs have send permissions
    32  	err = allHavePermission(ctx.StateWriter, permission.Send, accounts, ctx.Logger)
    33  	if err != nil {
    34  		return errors.Wrap(err, "at least one input lacks permission for SendTx")
    35  	}
    36  
    37  	// add outputs to accounts map
    38  	// if any outputs don't exist, all inputs must have CreateAccount perm
    39  	accounts, err = getOrMakeOutputs(ctx.StateWriter, accounts, ctx.tx.Outputs, ctx.Logger)
    40  	if err != nil {
    41  		return err
    42  	}
    43  
    44  	outTotal, err := validateOutputs(ctx.tx.Outputs)
    45  	if err != nil {
    46  		return err
    47  	}
    48  	if outTotal > inTotal {
    49  		return errors.ErrorCodeInsufficientFunds
    50  	}
    51  	if outTotal < inTotal {
    52  		return errors.ErrorCodeOverpayment
    53  	}
    54  	if outTotal == 0 {
    55  		return errors.ErrorCodeZeroPayment
    56  	}
    57  
    58  	// Good! Adjust accounts
    59  	err = adjustByInputs(accounts, ctx.tx.Inputs)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	err = adjustByOutputs(accounts, ctx.tx.Outputs)
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	for _, acc := range accounts {
    70  		err = ctx.StateWriter.UpdateAccount(acc)
    71  		if err != nil {
    72  			return err
    73  		}
    74  	}
    75  
    76  	for _, i := range ctx.tx.Inputs {
    77  		txe.Input(i.Address, nil)
    78  	}
    79  
    80  	for _, o := range ctx.tx.Outputs {
    81  		txe.Output(o.Address, nil)
    82  	}
    83  
    84  	return nil
    85  }