github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/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 "github.com/insight-chain/inb-go/core/types" 24 "math/big" 25 "regexp" 26 27 "github.com/insight-chain/inb-go/common" 28 ) 29 30 // The validation package contains validation checks for transactions 31 // - ABI-data validation 32 // - Transaction semantics validation 33 // The package provides warnings for typical pitfalls 34 35 type Validator struct { 36 db *AbiDb 37 } 38 39 func NewValidator(db *AbiDb) *Validator { 40 return &Validator{db} 41 } 42 func testSelector(selector string, data []byte) (*decodedCallData, error) { 43 if selector == "" { 44 return nil, fmt.Errorf("selector not found") 45 } 46 abiData, err := MethodSelectorToAbi(selector) 47 if err != nil { 48 return nil, err 49 } 50 info, err := parseCallData(data, string(abiData)) 51 if err != nil { 52 return nil, err 53 } 54 return info, nil 55 56 } 57 58 // validateCallData checks if the ABI-data + methodselector (if given) can be parsed and seems to match 59 func (v *Validator) validateCallData(msgs *ValidationMessages, data []byte, methodSelector *string) { 60 if len(data) == 0 { 61 return 62 } 63 if len(data) < 4 { 64 msgs.warn("Tx contains data which is not valid ABI") 65 return 66 } 67 if arglen := len(data) - 4; arglen%32 != 0 { 68 msgs.warn(fmt.Sprintf("Not ABI-encoded data; length should be a multiple of 32 (was %d)", arglen)) 69 } 70 var ( 71 info *decodedCallData 72 err error 73 ) 74 // Check the provided one 75 if methodSelector != nil { 76 info, err = testSelector(*methodSelector, data) 77 if err != nil { 78 msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err)) 79 } else { 80 msgs.info(info.String()) 81 //Successfull match. add to db if not there already (ignore errors there) 82 v.db.AddSignature(*methodSelector, data[:4]) 83 } 84 return 85 } 86 // Check the db 87 selector, err := v.db.LookupMethodSelector(data[:4]) 88 if err != nil { 89 msgs.warn(fmt.Sprintf("Tx contains data, but the ABI signature could not be found: %v", err)) 90 return 91 } 92 info, err = testSelector(selector, data) 93 if err != nil { 94 msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err)) 95 } else { 96 msgs.info(info.String()) 97 } 98 } 99 100 // validateSemantics checks if the transactions 'makes sense', and generate warnings for a couple of typical scenarios 101 func (v *Validator) validate(msgs *ValidationMessages, txargs *SendTxArgs, methodSelector *string) error { 102 // Prevent accidental erroneous usage of both 'input' and 'data' 103 if txargs.Data != nil && txargs.Input != nil && !bytes.Equal(*txargs.Data, *txargs.Input) { 104 // This is a showstopper 105 return errors.New(`Ambiguous request: both "data" and "input" are set and are not identical`) 106 } 107 var ( 108 data []byte 109 ) 110 // Place data on 'data', and nil 'input' 111 if txargs.Input != nil { 112 txargs.Data = txargs.Input 113 txargs.Input = nil 114 } 115 if txargs.Data != nil { 116 data = *txargs.Data 117 } 118 119 if txargs.To == nil && txargs.Types == types.Contract { 120 //Contract creation should contain sufficient data to deploy a contract 121 // A typical error is omitting sender due to some quirk in the javascript call 122 // e.g. https://github.com/ethereum/go-ethereum/issues/16106 123 if len(data) == 0 { 124 if txargs.Value.ToInt().Cmp(big.NewInt(0)) > 0 { 125 // Sending ether into black hole 126 return errors.New("Tx will create contract with value but empty code!") 127 } 128 // No value submitted at least 129 msgs.crit("Tx will create contract with empty code!") 130 } else if len(data) < 40 { //Arbitrary limit 131 msgs.warn(fmt.Sprintf("Tx will will create contract, but payload is suspiciously small (%d b)", len(data))) 132 } 133 // methodSelector should be nil for contract creation 134 if methodSelector != nil { 135 msgs.warn("Tx will create contract, but method selector supplied; indicating intent to call a method.") 136 } 137 138 } else { 139 if !txargs.To.ValidChecksum() { 140 msgs.warn("Invalid checksum on to-address") 141 } 142 // Normal transaction 143 if bytes.Equal(txargs.To.Address().Bytes(), common.Address{}.Bytes()) { 144 // Sending to 0 145 msgs.crit("Tx destination is the zero address!") 146 } 147 // Validate calldata 148 v.validateCallData(msgs, data, methodSelector) 149 } 150 return nil 151 } 152 153 // ValidateTransaction does a number of checks on the supplied transaction, and returns either a list of warnings, 154 // or an error, indicating that the transaction should be immediately rejected 155 func (v *Validator) ValidateTransaction(txArgs *SendTxArgs, methodSelector *string) (*ValidationMessages, error) { 156 msgs := &ValidationMessages{} 157 return msgs, v.validate(msgs, txArgs, methodSelector) 158 } 159 160 var Printable7BitAscii = regexp.MustCompile("^[A-Za-z0-9!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ]+$") 161 162 // ValidatePasswordFormat returns an error if the password is too short, or consists of characters 163 // outside the range of the printable 7bit ascii set 164 func ValidatePasswordFormat(password string) error { 165 if len(password) < 10 { 166 return errors.New("password too short (<10 characters)") 167 } 168 if !Printable7BitAscii.MatchString(password) { 169 return errors.New("password contains invalid characters - only 7bit printable ascii allowed") 170 } 171 return nil 172 }