github.com/koko1123/flow-go-1@v0.29.6/model/flow/transaction.go (about)

     1  package flow
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/koko1123/flow-go-1/model/fingerprint"
     8  	"github.com/onflow/flow-go/crypto"
     9  	"github.com/onflow/flow-go/crypto/hash"
    10  )
    11  
    12  // TransactionBody includes the main contents of a transaction
    13  type TransactionBody struct {
    14  
    15  	// A reference to a previous block
    16  	// A transaction is expired after specific number of blocks (defined by network) counting from this block
    17  	// for example, if block reference is pointing to a block with height of X and network limit is 10,
    18  	// a block with x+10 height is the last block that is allowed to include this transaction.
    19  	// user can adjust this reference to older blocks if he/she wants to make tx expire faster
    20  	ReferenceBlockID Identifier
    21  
    22  	// the transaction script as UTF-8 encoded Cadence source code
    23  	Script []byte
    24  
    25  	// arguments passed to the Cadence transaction
    26  	Arguments [][]byte
    27  
    28  	// Max amount of computation which is allowed to be done during this transaction
    29  	GasLimit uint64
    30  
    31  	// Account key used to propose the transaction
    32  	ProposalKey ProposalKey
    33  
    34  	// Account that pays for this transaction fees
    35  	Payer Address
    36  
    37  	// A ordered (ascending) list of addresses that scripts will touch their assets (including payer address)
    38  	// Accounts listed here all have to provide signatures
    39  	// Each account might provide multiple signatures (sum of weight should be at least 1)
    40  	// If code touches accounts that is not listed here, tx fails
    41  	Authorizers []Address
    42  
    43  	// List of account signatures excluding signature of the payer account
    44  	PayloadSignatures []TransactionSignature
    45  
    46  	// payer signature over the envelope (payload + payload signatures)
    47  	EnvelopeSignatures []TransactionSignature
    48  }
    49  
    50  // NewTransactionBody initializes and returns an empty transaction body
    51  func NewTransactionBody() *TransactionBody {
    52  	return &TransactionBody{}
    53  }
    54  
    55  func (tb TransactionBody) Fingerprint() []byte {
    56  	return fingerprint.Fingerprint(struct {
    57  		Payload            interface{}
    58  		PayloadSignatures  interface{}
    59  		EnvelopeSignatures interface{}
    60  	}{
    61  		Payload:            tb.payloadCanonicalForm(),
    62  		PayloadSignatures:  signaturesList(tb.PayloadSignatures).canonicalForm(),
    63  		EnvelopeSignatures: signaturesList(tb.EnvelopeSignatures).canonicalForm(),
    64  	})
    65  }
    66  
    67  func (tb TransactionBody) ByteSize() uint {
    68  	size := 0
    69  	size += len(tb.ReferenceBlockID)
    70  	size += len(tb.Script)
    71  	for _, arg := range tb.Arguments {
    72  		size += len(arg)
    73  	}
    74  	size += 8 // gas size
    75  	size += tb.ProposalKey.ByteSize()
    76  	size += AddressLength                       // payer address
    77  	size += len(tb.Authorizers) * AddressLength // Authorizers
    78  	for _, s := range tb.PayloadSignatures {
    79  		size += s.ByteSize()
    80  	}
    81  	for _, s := range tb.EnvelopeSignatures {
    82  		size += s.ByteSize()
    83  	}
    84  	return uint(size)
    85  }
    86  
    87  // InclusionEffort returns the inclusion effort of the transaction
    88  func (tb TransactionBody) InclusionEffort() uint64 {
    89  	// Hardcoded inclusion effort (of 1.0 UFix).
    90  	// Eventually this will be dynamic and will depend on the transaction properties
    91  	inclusionEffort := uint64(100_000_000)
    92  	return inclusionEffort
    93  }
    94  
    95  func (tb TransactionBody) ID() Identifier {
    96  	return MakeID(tb)
    97  }
    98  
    99  func (tb TransactionBody) Checksum() Identifier {
   100  	return MakeID(tb)
   101  }
   102  
   103  // SetScript sets the Cadence script for this transaction.
   104  func (tb *TransactionBody) SetScript(script []byte) *TransactionBody {
   105  	tb.Script = script
   106  	return tb
   107  }
   108  
   109  // SetArguments sets the Cadence arguments list for this transaction.
   110  func (tb *TransactionBody) SetArguments(args [][]byte) *TransactionBody {
   111  	tb.Arguments = args
   112  	return tb
   113  }
   114  
   115  // AddArgument adds an argument to the Cadence arguments list for this transaction.
   116  func (tb *TransactionBody) AddArgument(arg []byte) *TransactionBody {
   117  	tb.Arguments = append(tb.Arguments, arg)
   118  	return tb
   119  }
   120  
   121  // SetReferenceBlockID sets the reference block ID for this transaction.
   122  func (tb *TransactionBody) SetReferenceBlockID(blockID Identifier) *TransactionBody {
   123  	tb.ReferenceBlockID = blockID
   124  	return tb
   125  }
   126  
   127  // SetGasLimit sets the gas limit for this transaction.
   128  func (tb *TransactionBody) SetGasLimit(limit uint64) *TransactionBody {
   129  	tb.GasLimit = limit
   130  	return tb
   131  }
   132  
   133  // SetProposalKey sets the proposal key and sequence number for this transaction.
   134  //
   135  // The first two arguments specify the account key to be used, and the last argument is the sequence
   136  // number being declared.
   137  func (tb *TransactionBody) SetProposalKey(address Address, keyID uint64, sequenceNum uint64) *TransactionBody {
   138  	proposalKey := ProposalKey{
   139  		Address:        address,
   140  		KeyIndex:       keyID,
   141  		SequenceNumber: sequenceNum,
   142  	}
   143  	tb.ProposalKey = proposalKey
   144  	return tb
   145  }
   146  
   147  // SetPayer sets the payer account for this transaction.
   148  func (tb *TransactionBody) SetPayer(address Address) *TransactionBody {
   149  	tb.Payer = address
   150  	return tb
   151  }
   152  
   153  // AddAuthorizer adds an authorizer account to this transaction.
   154  func (tb *TransactionBody) AddAuthorizer(address Address) *TransactionBody {
   155  	tb.Authorizers = append(tb.Authorizers, address)
   156  	return tb
   157  }
   158  
   159  // Transaction is the smallest unit of task.
   160  type Transaction struct {
   161  	TransactionBody
   162  	Status           TransactionStatus
   163  	Events           []Event
   164  	ComputationSpent uint64
   165  	StartState       StateCommitment
   166  	EndState         StateCommitment
   167  }
   168  
   169  // MissingFields checks if a transaction is missing any required fields and returns those that are missing.
   170  func (tb *TransactionBody) MissingFields() []string {
   171  	// Required fields are Script, ReferenceBlockID, Payer
   172  	missingFields := make([]string, 0)
   173  
   174  	if len(tb.Script) == 0 {
   175  		missingFields = append(missingFields, TransactionFieldScript.String())
   176  	}
   177  
   178  	if tb.ReferenceBlockID == ZeroID {
   179  		missingFields = append(missingFields, TransactionFieldRefBlockID.String())
   180  	}
   181  
   182  	if tb.Payer == EmptyAddress {
   183  		missingFields = append(missingFields, TransactionFieldPayer.String())
   184  	}
   185  
   186  	return missingFields
   187  }
   188  
   189  // signerList returns a list of unique accounts required to sign this transaction.
   190  //
   191  // The list is returned in the following order:
   192  // 1. PROPOSER
   193  // 2. PAYER
   194  // 2. AUTHORIZERS (in insertion order)
   195  //
   196  // The only exception to the above ordering is for deduplication; if the same account
   197  // is used in multiple signing roles, only the first occurrence is included in the list.
   198  func (tb *TransactionBody) signerList() []Address {
   199  	signers := make([]Address, 0)
   200  	seen := make(map[Address]struct{})
   201  
   202  	var addSigner = func(address Address) {
   203  		_, ok := seen[address]
   204  		if ok {
   205  			return
   206  		}
   207  
   208  		signers = append(signers, address)
   209  		seen[address] = struct{}{}
   210  	}
   211  
   212  	if tb.ProposalKey.Address != EmptyAddress {
   213  		addSigner(tb.ProposalKey.Address)
   214  	}
   215  
   216  	if tb.Payer != EmptyAddress {
   217  		addSigner(tb.Payer)
   218  	}
   219  
   220  	for _, authorizer := range tb.Authorizers {
   221  		addSigner(authorizer)
   222  	}
   223  
   224  	return signers
   225  }
   226  
   227  // signerMap returns a mapping from address to signer index.
   228  func (tb *TransactionBody) signerMap() map[Address]int {
   229  	signers := make(map[Address]int)
   230  
   231  	for i, signer := range tb.signerList() {
   232  		signers[signer] = i
   233  	}
   234  
   235  	return signers
   236  }
   237  
   238  // SignPayload signs the transaction payload (TransactionDomainTag + payload) with the specified account key using the default transaction domain tag.
   239  //
   240  // The resulting signature is combined with the account address and key ID before
   241  // being added to the transaction.
   242  //
   243  // This function returns an error if the signature cannot be generated.
   244  func (tb *TransactionBody) SignPayload(
   245  	address Address,
   246  	keyID uint64,
   247  	privateKey crypto.PrivateKey,
   248  	hasher hash.Hasher,
   249  ) error {
   250  	sig, err := tb.Sign(tb.PayloadMessage(), privateKey, hasher)
   251  
   252  	if err != nil {
   253  		return fmt.Errorf("failed to sign transaction payload with given key: %w", err)
   254  	}
   255  
   256  	tb.AddPayloadSignature(address, keyID, sig)
   257  
   258  	return nil
   259  }
   260  
   261  // SignEnvelope signs the full transaction (TransactionDomainTag + payload + payload signatures) with the specified account key using the default transaction domain tag.
   262  //
   263  // The resulting signature is combined with the account address and key ID before
   264  // being added to the transaction.
   265  //
   266  // This function returns an error if the signature cannot be generated.
   267  func (tb *TransactionBody) SignEnvelope(
   268  	address Address,
   269  	keyID uint64,
   270  	privateKey crypto.PrivateKey,
   271  	hasher hash.Hasher,
   272  ) error {
   273  	sig, err := tb.Sign(tb.EnvelopeMessage(), privateKey, hasher)
   274  
   275  	if err != nil {
   276  		return fmt.Errorf("failed to sign transaction envelope with given key: %w", err)
   277  	}
   278  
   279  	tb.AddEnvelopeSignature(address, keyID, sig)
   280  
   281  	return nil
   282  }
   283  
   284  // Sign signs the data (transaction_tag + message) with the specified private key
   285  // and hasher.
   286  //
   287  // This function returns an error if:
   288  //   - crypto.InvalidInputsError if the private key cannot sign with the given hasher
   289  //   - other error if an unexpected error occurs
   290  func (tb *TransactionBody) Sign(
   291  	message []byte,
   292  	privateKey crypto.PrivateKey,
   293  	hasher hash.Hasher,
   294  ) ([]byte, error) {
   295  	message = append(TransactionDomainTag[:], message...)
   296  	sig, err := privateKey.Sign(message, hasher)
   297  	if err != nil {
   298  		return nil, fmt.Errorf("failed to sign message with given key: %w", err)
   299  	}
   300  
   301  	return sig, nil
   302  }
   303  
   304  // AddPayloadSignature adds a payload signature to the transaction for the given address and key ID.
   305  func (tb *TransactionBody) AddPayloadSignature(address Address, keyID uint64, sig []byte) *TransactionBody {
   306  	s := tb.createSignature(address, keyID, sig)
   307  
   308  	tb.PayloadSignatures = append(tb.PayloadSignatures, s)
   309  	sort.Slice(tb.PayloadSignatures, compareSignatures(tb.PayloadSignatures))
   310  
   311  	return tb
   312  }
   313  
   314  // AddEnvelopeSignature adds an envelope signature to the transaction for the given address and key ID.
   315  func (tb *TransactionBody) AddEnvelopeSignature(address Address, keyID uint64, sig []byte) *TransactionBody {
   316  	s := tb.createSignature(address, keyID, sig)
   317  
   318  	tb.EnvelopeSignatures = append(tb.EnvelopeSignatures, s)
   319  	sort.Slice(tb.EnvelopeSignatures, compareSignatures(tb.EnvelopeSignatures))
   320  
   321  	return tb
   322  }
   323  
   324  func (tb *TransactionBody) createSignature(address Address, keyID uint64, sig []byte) TransactionSignature {
   325  	signerIndex, signerExists := tb.signerMap()[address]
   326  	if !signerExists {
   327  		signerIndex = -1
   328  	}
   329  
   330  	return TransactionSignature{
   331  		Address:     address,
   332  		SignerIndex: signerIndex,
   333  		KeyIndex:    keyID,
   334  		Signature:   sig,
   335  	}
   336  }
   337  
   338  func (tb *TransactionBody) PayloadMessage() []byte {
   339  	return fingerprint.Fingerprint(tb.payloadCanonicalForm())
   340  }
   341  
   342  func (tb *TransactionBody) payloadCanonicalForm() interface{} {
   343  	authorizers := make([][]byte, len(tb.Authorizers))
   344  	for i, auth := range tb.Authorizers {
   345  		authorizers[i] = auth.Bytes()
   346  	}
   347  
   348  	return struct {
   349  		Script                    []byte
   350  		Arguments                 [][]byte
   351  		ReferenceBlockID          []byte
   352  		GasLimit                  uint64
   353  		ProposalKeyAddress        []byte
   354  		ProposalKeyID             uint64
   355  		ProposalKeySequenceNumber uint64
   356  		Payer                     []byte
   357  		Authorizers               [][]byte
   358  	}{
   359  		Script:                    tb.Script,
   360  		Arguments:                 tb.Arguments,
   361  		ReferenceBlockID:          tb.ReferenceBlockID[:],
   362  		GasLimit:                  tb.GasLimit,
   363  		ProposalKeyAddress:        tb.ProposalKey.Address.Bytes(),
   364  		ProposalKeyID:             tb.ProposalKey.KeyIndex,
   365  		ProposalKeySequenceNumber: tb.ProposalKey.SequenceNumber,
   366  		Payer:                     tb.Payer.Bytes(),
   367  		Authorizers:               authorizers,
   368  	}
   369  }
   370  
   371  // EnvelopeMessage returns the signable message for transaction envelope.
   372  //
   373  // This message is only signed by the payer account.
   374  func (tb *TransactionBody) EnvelopeMessage() []byte {
   375  	return fingerprint.Fingerprint(tb.envelopeCanonicalForm())
   376  }
   377  
   378  func (tb *TransactionBody) envelopeCanonicalForm() interface{} {
   379  	return struct {
   380  		Payload           interface{}
   381  		PayloadSignatures interface{}
   382  	}{
   383  		tb.payloadCanonicalForm(),
   384  		signaturesList(tb.PayloadSignatures).canonicalForm(),
   385  	}
   386  }
   387  
   388  func (tx *Transaction) PayloadMessage() []byte {
   389  	return fingerprint.Fingerprint(tx.TransactionBody.payloadCanonicalForm())
   390  }
   391  
   392  // Checksum provides a cryptographic commitment for a chunk content
   393  func (tx *Transaction) Checksum() Identifier {
   394  	return MakeID(tx)
   395  }
   396  
   397  func (tx *Transaction) String() string {
   398  	return fmt.Sprintf("Transaction %v submitted by %v (block %v)",
   399  		tx.ID(), tx.Payer.Hex(), tx.ReferenceBlockID)
   400  }
   401  
   402  // TransactionStatus represents the status of a transaction.
   403  type TransactionStatus int
   404  
   405  const (
   406  	// TransactionStatusUnknown indicates that the transaction status is not known.
   407  	TransactionStatusUnknown TransactionStatus = iota
   408  	// TransactionStatusPending is the status of a pending transaction.
   409  	TransactionStatusPending
   410  	// TransactionStatusFinalized is the status of a finalized transaction.
   411  	TransactionStatusFinalized
   412  	// TransactionStatusExecuted is the status of an executed transaction.
   413  	TransactionStatusExecuted
   414  	// TransactionStatusSealed is the status of a sealed transaction.
   415  	TransactionStatusSealed
   416  	// TransactionStatusExpired is the status of an expired transaction.
   417  	TransactionStatusExpired
   418  )
   419  
   420  // String returns the string representation of a transaction status.
   421  func (s TransactionStatus) String() string {
   422  	return [...]string{"UNKNOWN", "PENDING", "FINALIZED", "EXECUTED", "SEALED", "EXPIRED"}[s]
   423  }
   424  
   425  // TransactionField represents a required transaction field.
   426  type TransactionField int
   427  
   428  const (
   429  	TransactionFieldUnknown TransactionField = iota
   430  	TransactionFieldScript
   431  	TransactionFieldRefBlockID
   432  	TransactionFieldPayer
   433  )
   434  
   435  // String returns the string representation of a transaction field.
   436  func (f TransactionField) String() string {
   437  	return [...]string{"Unknown", "Script", "ReferenceBlockID", "Payer"}[f]
   438  }
   439  
   440  // A ProposalKey is the key that specifies the proposal key and sequence number for a transaction.
   441  type ProposalKey struct {
   442  	Address        Address
   443  	KeyIndex       uint64
   444  	SequenceNumber uint64
   445  }
   446  
   447  // ByteSize returns the byte size of the proposal key
   448  func (p ProposalKey) ByteSize() int {
   449  	keyIDLen := 8
   450  	sequenceNumberLen := 8
   451  	return len(p.Address) + keyIDLen + sequenceNumberLen
   452  }
   453  
   454  // A TransactionSignature is a signature associated with a specific account key.
   455  type TransactionSignature struct {
   456  	Address     Address
   457  	SignerIndex int
   458  	KeyIndex    uint64
   459  	Signature   []byte
   460  }
   461  
   462  // String returns the string representation of a transaction signature.
   463  func (s TransactionSignature) String() string {
   464  	return fmt.Sprintf("Address: %s. SignerIndex: %d. KeyID: %d. Signature: %s",
   465  		s.Address, s.SignerIndex, s.KeyIndex, s.Signature)
   466  }
   467  
   468  // ByteSize returns the byte size of the transaction signature
   469  func (s TransactionSignature) ByteSize() int {
   470  	signerIndexLen := 8
   471  	keyIDLen := 8
   472  	return len(s.Address) + signerIndexLen + keyIDLen + len(s.Signature)
   473  }
   474  
   475  func (s TransactionSignature) Fingerprint() []byte {
   476  	return fingerprint.Fingerprint(s.canonicalForm())
   477  }
   478  
   479  func (s TransactionSignature) canonicalForm() interface{} {
   480  	return struct {
   481  		SignerIndex uint
   482  		KeyID       uint
   483  		Signature   []byte
   484  	}{
   485  		SignerIndex: uint(s.SignerIndex), // int is not RLP-serializable
   486  		KeyID:       uint(s.KeyIndex),    // int is not RLP-serializable
   487  		Signature:   s.Signature,
   488  	}
   489  }
   490  
   491  func compareSignatures(signatures []TransactionSignature) func(i, j int) bool {
   492  	return func(i, j int) bool {
   493  		sigA := signatures[i]
   494  		sigB := signatures[j]
   495  
   496  		if sigA.SignerIndex == sigB.SignerIndex {
   497  			return sigA.KeyIndex < sigB.KeyIndex
   498  		}
   499  
   500  		return sigA.SignerIndex < sigB.SignerIndex
   501  	}
   502  }
   503  
   504  type signaturesList []TransactionSignature
   505  
   506  func (s signaturesList) canonicalForm() interface{} {
   507  	signatures := make([]interface{}, len(s))
   508  
   509  	for i, signature := range s {
   510  		signatures[i] = signature.canonicalForm()
   511  	}
   512  
   513  	return signatures
   514  }