github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/transactionpool/standard.go (about) 1 package transactionpool 2 3 import ( 4 "errors" 5 6 "github.com/NebulousLabs/Sia/encoding" 7 "github.com/NebulousLabs/Sia/modules" 8 "github.com/NebulousLabs/Sia/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 transaciton. 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 (tp *TransactionPool) 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 func (tp *TransactionPool) IsStandardTransaction(t types.Transaction) error { 59 // Check that the size of the transaction does not exceed the standard 60 // established in Standard.md. Larger transactions are a DOS vector, 61 // because someone can fill a large transaction with a bunch of signatures 62 // that require hashing the entire transaction. Several hundred megabytes 63 // of hashing can be required of a verifier. Enforcing this rule makes it 64 // more difficult for attackers to exploid this DOS vector, though a miner 65 // with sufficient power could still create unfriendly blocks. 66 if len(encoding.Marshal(t)) > modules.TransactionSizeLimit { 67 return modules.ErrLargeTransaction 68 } 69 70 // Check that all public keys are of a recognized type. Need to check all 71 // of the UnlockConditions, which currently can appear in 3 separate fields 72 // of the transaction. Unrecognized types are ignored because a softfork 73 // may make certain unrecognized signatures invalid, and this node cannot 74 // tell which sigantures are the invalid ones. 75 for _, sci := range t.SiacoinInputs { 76 err := tp.checkUnlockConditions(sci.UnlockConditions) 77 if err != nil { 78 return err 79 } 80 } 81 for _, fcr := range t.FileContractRevisions { 82 err := tp.checkUnlockConditions(fcr.UnlockConditions) 83 if err != nil { 84 return err 85 } 86 } 87 for _, sfi := range t.SiafundInputs { 88 err := tp.checkUnlockConditions(sfi.UnlockConditions) 89 if err != nil { 90 return err 91 } 92 } 93 94 // Check that all arbitrary data is prefixed using the recognized set of 95 // prefixes. The allowed prefixes include a 'NonSia' prefix for truly 96 // arbitrary data. Blocking all other prefixes allows arbitrary data to be 97 // used to orchestrate more complicated soft forks in the future without 98 // putting older nodes at risk of violating the new rules. 99 var prefix types.Specifier 100 for _, arb := range t.ArbitraryData { 101 // Check for a whilelisted prefix. 102 copy(prefix[:], arb) 103 if prefix == modules.PrefixHostAnnouncement || 104 prefix == modules.PrefixNonSia { 105 continue 106 } 107 108 return modules.ErrInvalidArbPrefix 109 } 110 return nil 111 } 112 113 // IsStandardTransactionSet checks that all transacitons of a set follow the 114 // IsStandard guidelines, and that the set as a whole follows the guidelines as 115 // well. 116 func (tp *TransactionPool) IsStandardTransactionSet(ts []types.Transaction) error { 117 // Check that the set is a reasonable size. 118 totalSize := 0 119 for i := range ts { 120 totalSize += len(encoding.Marshal(ts[i])) 121 if totalSize > modules.TransactionSetSizeLimit { 122 return modules.ErrLargeTransactionSet 123 } 124 } 125 126 // Check that each transaction is acceptable. 127 for i := range ts { 128 err := tp.IsStandardTransaction(ts[i]) 129 if err != nil { 130 return err 131 } 132 } 133 return nil 134 }