gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/transactionpool/standard.go (about)

     1  package transactionpool
     2  
     3  import (
     4  	"errors"
     5  
     6  	"gitlab.com/SiaPrime/SiaPrime/encoding"
     7  	"gitlab.com/SiaPrime/SiaPrime/modules"
     8  	"gitlab.com/SiaPrime/SiaPrime/types"
     9  )
    10  
    11  // standard.go adds extra rules to transactions which help preserve network
    12  // health and provides flexibility for future soft forks and tweaks to the
    13  // network.
    14  //
    15  // Rule: Transaction size is limited
    16  //		There is a DoS vector where large transactions can both contain many
    17  //		signatures, and have each signature's CoveredFields object cover a
    18  //		unique but large portion of the transaction. A 1mb transaction could
    19  //		force a verifier to hash very large volumes of data, which takes a long
    20  //		time on nonspecialized hardware.
    21  //
    22  // Rule: Foreign signature algorithms are rejected.
    23  //		There are plans to add newer, faster signature algorithms to Sia as the
    24  //		project matures and the need for increased verification speed grows.
    25  //		Foreign signatures are allowed into the blockchain, where they are
    26  //		accepted as valid. Hoewver, if there has been a soft-fork, the foreign
    27  //		signatures might actually be invalid. This rule protects legacy miners
    28  //		from including potentially invalid transactions in their blocks.
    29  //
    30  // Rule: The types of allowed arbitrary data are limited
    31  //		The arbitrary data field can be used to orchestrate soft-forks to Sia
    32  //		that add features. Legacy miners are at risk of creating invalid blocks
    33  //		if they include arbitrary data which has meanings that the legacy miner
    34  //		doesn't understand.
    35  //
    36  // Rule: The transaction set size is limited.
    37  //		A group of dependent transactions cannot exceed 100kb to limit how
    38  //		quickly the transaction pool can be filled with new transactions.
    39  
    40  // checkUnlockConditions looks at the UnlockConditions and verifies that all
    41  // public keys are recognized. Unrecognized public keys are automatically
    42  // accepted as valid by the consnensus set, but rejected by the transaction
    43  // pool. This allows new types of keys to be added via a softfork without
    44  // alienating all of the older nodes.
    45  func checkUnlockConditions(uc types.UnlockConditions) error {
    46  	for _, pk := range uc.PublicKeys {
    47  		if pk.Algorithm != types.SignatureEntropy &&
    48  			pk.Algorithm != types.SignatureEd25519 {
    49  			return errors.New("unrecognized key type in transaction")
    50  		}
    51  	}
    52  
    53  	return nil
    54  }
    55  
    56  // isStandardTransaction enforces extra rules such as a transaction size limit.
    57  // These rules can be altered without disrupting consensus.
    58  //
    59  // The size of the transaction is returned so that the transaction does not need
    60  // to be encoded multiple times.
    61  func isStandardTransaction(t types.Transaction) (uint64, error) {
    62  	// Check that the size of the transaction does not exceed the standard
    63  	// established in Standard.md. Larger transactions are a DOS vector,
    64  	// because someone can fill a large transaction with a bunch of signatures
    65  	// that require hashing the entire transaction. Several hundred megabytes
    66  	// of hashing can be required of a verifier. Enforcing this rule makes it
    67  	// more difficult for attackers to exploid this DOS vector, though a miner
    68  	// with sufficient power could still create unfriendly blocks.
    69  	tlen := len(encoding.Marshal(t))
    70  	if tlen > modules.TransactionSizeLimit {
    71  		return 0, modules.ErrLargeTransaction
    72  	}
    73  
    74  	// Check that all public keys are of a recognized type. Need to check all
    75  	// of the UnlockConditions, which currently can appear in 3 separate fields
    76  	// of the transaction. Unrecognized types are ignored because a softfork
    77  	// may make certain unrecognized signatures invalid, and this node cannot
    78  	// tell which signatures are the invalid ones.
    79  	for _, sci := range t.SiacoinInputs {
    80  		err := checkUnlockConditions(sci.UnlockConditions)
    81  		if err != nil {
    82  			return 0, err
    83  		}
    84  	}
    85  	for _, fcr := range t.FileContractRevisions {
    86  		err := checkUnlockConditions(fcr.UnlockConditions)
    87  		if err != nil {
    88  			return 0, err
    89  		}
    90  	}
    91  	for _, sfi := range t.SiafundInputs {
    92  		err := checkUnlockConditions(sfi.UnlockConditions)
    93  		if err != nil {
    94  			return 0, err
    95  		}
    96  	}
    97  
    98  	// Check that all arbitrary data is prefixed using the recognized set of
    99  	// prefixes. The allowed prefixes include a 'NonSia' prefix for truly
   100  	// arbitrary data. Blocking all other prefixes allows arbitrary data to be
   101  	// used to orchestrate more complicated soft forks in the future without
   102  	// putting older nodes at risk of violating the new rules.
   103  	var prefix types.Specifier
   104  	for _, arb := range t.ArbitraryData {
   105  		// Check for a whilelisted prefix.
   106  		copy(prefix[:], arb)
   107  		if prefix == modules.PrefixHostAnnouncement ||
   108  			prefix == modules.PrefixNonSia ||
   109  			prefix == modules.PrefixFileContractIdentifier {
   110  			continue
   111  		}
   112  
   113  		return 0, modules.ErrInvalidArbPrefix
   114  	}
   115  	return uint64(tlen), nil
   116  }
   117  
   118  // isStandardTransactionSet checks that all transacitons of a set follow the
   119  // IsStandard guidelines, and that the set as a whole follows the guidelines as
   120  // well.
   121  //
   122  // The size of the transaction set is returned so that the encoding only needs
   123  // to happen once.
   124  func isStandardTransactionSet(ts []types.Transaction) (uint64, error) {
   125  	// Check that each transaction is acceptable, while also making sure that
   126  	// the size of the whole set is legal.
   127  	var totalSize uint64
   128  	for i := range ts {
   129  		tSize, err := isStandardTransaction(ts[i])
   130  		if err != nil {
   131  			return 0, err
   132  		}
   133  		totalSize += tSize
   134  		if totalSize > modules.TransactionSetSizeLimit {
   135  			return 0, modules.ErrLargeTransactionSet
   136  		}
   137  
   138  	}
   139  	return totalSize, nil
   140  }