github.com/luckypickle/go-ethereum-vet@v1.14.2/signer/core/validation.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "math/big" 24 25 "github.com/luckypickle/go-ethereum-vet/common" 26 ) 27 28 // The validation package contains validation checks for transactions 29 // - ABI-data validation 30 // - Transaction semantics validation 31 // The package provides warnings for typical pitfalls 32 33 func (vs *ValidationMessages) crit(msg string) { 34 vs.Messages = append(vs.Messages, ValidationInfo{"CRITICAL", msg}) 35 } 36 func (vs *ValidationMessages) warn(msg string) { 37 vs.Messages = append(vs.Messages, ValidationInfo{"WARNING", msg}) 38 } 39 func (vs *ValidationMessages) info(msg string) { 40 vs.Messages = append(vs.Messages, ValidationInfo{"Info", msg}) 41 } 42 43 type Validator struct { 44 db *AbiDb 45 } 46 47 func NewValidator(db *AbiDb) *Validator { 48 return &Validator{db} 49 } 50 func testSelector(selector string, data []byte) (*decodedCallData, error) { 51 if selector == "" { 52 return nil, fmt.Errorf("selector not found") 53 } 54 abiData, err := MethodSelectorToAbi(selector) 55 if err != nil { 56 return nil, err 57 } 58 info, err := parseCallData(data, string(abiData)) 59 if err != nil { 60 return nil, err 61 } 62 return info, nil 63 64 } 65 66 // validateCallData checks if the ABI-data + methodselector (if given) can be parsed and seems to match 67 func (v *Validator) validateCallData(msgs *ValidationMessages, data []byte, methodSelector *string) { 68 if len(data) == 0 { 69 return 70 } 71 if len(data) < 4 { 72 msgs.warn("Tx contains data which is not valid ABI") 73 return 74 } 75 var ( 76 info *decodedCallData 77 err error 78 ) 79 // Check the provided one 80 if methodSelector != nil { 81 info, err = testSelector(*methodSelector, data) 82 if err != nil { 83 msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err)) 84 } else { 85 msgs.info(info.String()) 86 //Successfull match. add to db if not there already (ignore errors there) 87 v.db.AddSignature(*methodSelector, data[:4]) 88 } 89 return 90 } 91 // Check the db 92 selector, err := v.db.LookupMethodSelector(data[:4]) 93 if err != nil { 94 msgs.warn(fmt.Sprintf("Tx contains data, but the ABI signature could not be found: %v", err)) 95 return 96 } 97 info, err = testSelector(selector, data) 98 if err != nil { 99 msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err)) 100 } else { 101 msgs.info(info.String()) 102 } 103 } 104 105 // validateSemantics checks if the transactions 'makes sense', and generate warnings for a couple of typical scenarios 106 func (v *Validator) validate(msgs *ValidationMessages, txargs *SendTxArgs, methodSelector *string) error { 107 // Prevent accidental erroneous usage of both 'input' and 'data' 108 if txargs.Data != nil && txargs.Input != nil && !bytes.Equal(*txargs.Data, *txargs.Input) { 109 // This is a showstopper 110 return errors.New(`Ambiguous request: both "data" and "input" are set and are not identical`) 111 } 112 var ( 113 data []byte 114 ) 115 // Place data on 'data', and nil 'input' 116 if txargs.Input != nil { 117 txargs.Data = txargs.Input 118 txargs.Input = nil 119 } 120 if txargs.Data != nil { 121 data = *txargs.Data 122 } 123 124 if txargs.To == nil { 125 //Contract creation should contain sufficient data to deploy a contract 126 // A typical error is omitting sender due to some quirk in the javascript call 127 // e.g. https://github.com/luckypickle/go-ethereum-vet/issues/16106 128 if len(data) == 0 { 129 if txargs.Value.ToInt().Cmp(big.NewInt(0)) > 0 { 130 // Sending ether into black hole 131 return errors.New("Tx will create contract with value but empty code!") 132 } 133 // No value submitted at least 134 msgs.crit("Tx will create contract with empty code!") 135 } else if len(data) < 40 { //Arbitrary limit 136 msgs.warn(fmt.Sprintf("Tx will will create contract, but payload is suspiciously small (%d b)", len(data))) 137 } 138 // methodSelector should be nil for contract creation 139 if methodSelector != nil { 140 msgs.warn("Tx will create contract, but method selector supplied; indicating intent to call a method.") 141 } 142 143 } else { 144 if !txargs.To.ValidChecksum() { 145 msgs.warn("Invalid checksum on to-address") 146 } 147 // Normal transaction 148 if bytes.Equal(txargs.To.Address().Bytes(), common.Address{}.Bytes()) { 149 // Sending to 0 150 msgs.crit("Tx destination is the zero address!") 151 } 152 // Validate calldata 153 v.validateCallData(msgs, data, methodSelector) 154 } 155 return nil 156 } 157 158 // ValidateTransaction does a number of checks on the supplied transaction, and returns either a list of warnings, 159 // or an error, indicating that the transaction should be immediately rejected 160 func (v *Validator) ValidateTransaction(txArgs *SendTxArgs, methodSelector *string) (*ValidationMessages, error) { 161 msgs := &ValidationMessages{} 162 return msgs, v.validate(msgs, txArgs, methodSelector) 163 }