validation.go 5.2 KB

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