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 }