github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/access/rest/request/transaction.go (about) 1 package request 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/onflow/flow-go/engine/access/rest/models" 8 "github.com/onflow/flow-go/engine/access/rest/util" 9 "github.com/onflow/flow-go/engine/common/rpc/convert" 10 "github.com/onflow/flow-go/model/flow" 11 ) 12 13 const maxAuthorizers = 100 14 const maxAllowedScriptArguments = 100 15 16 type Transaction flow.TransactionBody 17 18 func (t *Transaction) Parse(raw io.Reader, chain flow.Chain) error { 19 var tx models.TransactionsBody 20 err := parseBody(raw, &tx) 21 if err != nil { 22 return err 23 } 24 25 if tx.ProposalKey == nil { 26 return fmt.Errorf("proposal key not provided") 27 } 28 if tx.Script == "" { 29 return fmt.Errorf("script not provided") 30 } 31 if tx.Payer == "" { 32 return fmt.Errorf("payer not provided") 33 } 34 if len(tx.Authorizers) > maxAuthorizers { 35 return fmt.Errorf("too many authorizers. Maximum authorizers allowed: %d", maxAuthorizers) 36 } 37 if len(tx.Arguments) > maxAllowedScriptArguments { 38 return fmt.Errorf("too many arguments. Maximum arguments allowed: %d", maxAllowedScriptArguments) 39 } 40 if tx.ReferenceBlockId == "" { 41 return fmt.Errorf("reference block not provided") 42 } 43 if len(tx.EnvelopeSignatures) == 0 { 44 return fmt.Errorf("envelope signatures not provided") 45 } 46 47 var args Arguments 48 err = args.Parse(tx.Arguments) 49 if err != nil { 50 return err 51 } 52 53 payer, err := ParseAddress(tx.Payer, chain) 54 if err != nil { 55 return fmt.Errorf("invalid payer: %w", err) 56 } 57 58 auths := make([]flow.Address, len(tx.Authorizers)) 59 for i, auth := range tx.Authorizers { 60 a, err := ParseAddress(auth, chain) 61 if err != nil { 62 return err 63 } 64 65 auths[i] = a 66 } 67 68 var proposal ProposalKey 69 err = proposal.Parse(*tx.ProposalKey, chain) 70 if err != nil { 71 return err 72 } 73 74 var payloadSigs TransactionSignatures 75 err = payloadSigs.Parse(tx.PayloadSignatures, chain) 76 if err != nil { 77 return err 78 } 79 80 var envelopeSigs TransactionSignatures 81 err = envelopeSigs.Parse(tx.EnvelopeSignatures, chain) 82 if err != nil { 83 return err 84 } 85 86 // script comes in as a base64 encoded string, decode base64 back to a string here 87 script, err := util.FromBase64(tx.Script) 88 if err != nil { 89 return fmt.Errorf("invalid transaction script encoding") 90 } 91 92 var blockID ID 93 err = blockID.Parse(tx.ReferenceBlockId) 94 if err != nil { 95 return fmt.Errorf("invalid reference block ID: %w", err) 96 } 97 98 gasLimit, err := util.ToUint64(tx.GasLimit) 99 if err != nil { 100 return fmt.Errorf("invalid gas limit: %w", err) 101 } 102 103 flowTransaction := flow.TransactionBody{ 104 ReferenceBlockID: blockID.Flow(), 105 Script: script, 106 Arguments: args.Flow(), 107 GasLimit: gasLimit, 108 ProposalKey: proposal.Flow(), 109 Payer: payer, 110 Authorizers: auths, 111 PayloadSignatures: payloadSigs.Flow(), 112 EnvelopeSignatures: envelopeSigs.Flow(), 113 } 114 115 // we use the gRPC method of converting the incoming transaction to a Flow transaction since 116 // it sets the signer_index appropriately. 117 entityTransaction := convert.TransactionToMessage(flowTransaction) 118 flowTx, err := convert.MessageToTransaction(entityTransaction, chain) 119 if err != nil { 120 return err 121 } 122 123 *t = Transaction(flowTx) 124 125 return nil 126 } 127 128 func (t Transaction) Flow() flow.TransactionBody { 129 return flow.TransactionBody(t) 130 }