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  }