cmd/clef, signer: initial poc of the standalone signer (#16154)
* signer: introduce external signer command
* cmd/signer, rpc: Implement new signer. Add info about remote user to Context
* signer: refactored request/response, made use of urfave.cli
* cmd/signer: Use common flags
* cmd/signer: methods to validate calldata against abi
* cmd/signer: work on abi parser
* signer: add mutex around UI
* cmd/signer: add json 4byte directory, remove passwords from api
* cmd/signer: minor changes
* cmd/signer: Use ErrRequestDenied, enable lightkdf
* cmd/signer: implement tests
* cmd/signer: made possible for UI to modify tx parameters
* cmd/signer: refactors, removed channels in ui comms, added UI-api via stdin/out
* cmd/signer: Made lowercase json-definitions, added UI-signer test functionality
* cmd/signer: update documentation
* cmd/signer: fix bugs, improve abi detection, abi argument display
* cmd/signer: minor change in json format
* cmd/signer: rework json communication
* cmd/signer: implement mixcase addresses in API, fix json id bug
* cmd/signer: rename fromaccount, update pythonpoc with new json encoding format
* cmd/signer: make use of new abi interface
* signer: documentation
* signer/main: remove redundant option
* signer: implement audit logging
* signer: create package 'signer', minor changes
* common: add 0x-prefix to mixcaseaddress in json marshalling + validation
* signer, rules, storage: implement rules + ephemeral storage for signer rules
* signer: implement OnApprovedTx, change signing response (API BREAKAGE)
* signer: refactoring + documentation
* signer/rules: implement dispatching to next handler
* signer: docs
* signer/rules: hide json-conversion from users, ensure context is cleaned
* signer: docs
* signer: implement validation rules, change signature of call_info
* signer: fix log flaw with string pointer
* signer: implement custom 4byte databsae that saves submitted signatures
* signer/storage: implement aes-gcm-backed credential storage
* accounts: implement json unmarshalling of url
* signer: fix listresponse, fix gas->uint64
* node: make http/ipc start methods public
* signer: add ipc capability+review concerns
* accounts: correct docstring
* signer: address review concerns
* rpc: go fmt -s
* signer: review concerns+ baptize Clef
* signer,node: move Start-functions to separate file
* signer: formatting
2018-04-16 15:04:32 +03:00
|
|
|
// Copyright 2018 The go-ethereum Authors
|
|
|
|
// This file is part of go-ethereum.
|
|
|
|
//
|
|
|
|
// go-ethereum is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// go-ethereum is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
)
|
|
|
|
|
|
|
|
// The validation package contains validation checks for transactions
|
|
|
|
// - ABI-data validation
|
|
|
|
// - Transaction semantics validation
|
|
|
|
// The package provides warnings for typical pitfalls
|
|
|
|
|
|
|
|
func (vs *ValidationMessages) crit(msg string) {
|
|
|
|
vs.Messages = append(vs.Messages, ValidationInfo{"CRITICAL", msg})
|
|
|
|
}
|
|
|
|
func (vs *ValidationMessages) warn(msg string) {
|
|
|
|
vs.Messages = append(vs.Messages, ValidationInfo{"WARNING", msg})
|
|
|
|
}
|
|
|
|
func (vs *ValidationMessages) info(msg string) {
|
|
|
|
vs.Messages = append(vs.Messages, ValidationInfo{"Info", msg})
|
|
|
|
}
|
|
|
|
|
|
|
|
type Validator struct {
|
|
|
|
db *AbiDb
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewValidator(db *AbiDb) *Validator {
|
|
|
|
return &Validator{db}
|
|
|
|
}
|
|
|
|
func testSelector(selector string, data []byte) (*decodedCallData, error) {
|
|
|
|
if selector == "" {
|
|
|
|
return nil, fmt.Errorf("selector not found")
|
|
|
|
}
|
|
|
|
abiData, err := MethodSelectorToAbi(selector)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
info, err := parseCallData(data, string(abiData))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return info, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// validateCallData checks if the ABI-data + methodselector (if given) can be parsed and seems to match
|
|
|
|
func (v *Validator) validateCallData(msgs *ValidationMessages, data []byte, methodSelector *string) {
|
|
|
|
if len(data) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(data) < 4 {
|
|
|
|
msgs.warn("Tx contains data which is not valid ABI")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
info *decodedCallData
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
// Check the provided one
|
|
|
|
if methodSelector != nil {
|
|
|
|
info, err = testSelector(*methodSelector, data)
|
|
|
|
if err != nil {
|
|
|
|
msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err))
|
|
|
|
} else {
|
|
|
|
msgs.info(info.String())
|
|
|
|
//Successfull match. add to db if not there already (ignore errors there)
|
|
|
|
v.db.AddSignature(*methodSelector, data[:4])
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Check the db
|
|
|
|
selector, err := v.db.LookupMethodSelector(data[:4])
|
|
|
|
if err != nil {
|
|
|
|
msgs.warn(fmt.Sprintf("Tx contains data, but the ABI signature could not be found: %v", err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
info, err = testSelector(selector, data)
|
|
|
|
if err != nil {
|
|
|
|
msgs.warn(fmt.Sprintf("Tx contains data, but provided ABI signature could not be matched: %v", err))
|
|
|
|
} else {
|
|
|
|
msgs.info(info.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// validateSemantics checks if the transactions 'makes sense', and generate warnings for a couple of typical scenarios
|
|
|
|
func (v *Validator) validate(msgs *ValidationMessages, txargs *SendTxArgs, methodSelector *string) error {
|
|
|
|
// Prevent accidental erroneous usage of both 'input' and 'data'
|
|
|
|
if txargs.Data != nil && txargs.Input != nil && !bytes.Equal(*txargs.Data, *txargs.Input) {
|
|
|
|
// This is a showstopper
|
|
|
|
return errors.New(`Ambiguous request: both "data" and "input" are set and are not identical`)
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
data []byte
|
|
|
|
)
|
|
|
|
// Place data on 'data', and nil 'input'
|
|
|
|
if txargs.Input != nil {
|
|
|
|
txargs.Data = txargs.Input
|
|
|
|
txargs.Input = nil
|
|
|
|
}
|
|
|
|
if txargs.Data != nil {
|
|
|
|
data = *txargs.Data
|
|
|
|
}
|
|
|
|
|
|
|
|
if txargs.To == nil {
|
|
|
|
//Contract creation should contain sufficient data to deploy a contract
|
|
|
|
// A typical error is omitting sender due to some quirk in the javascript call
|
|
|
|
// e.g. https://github.com/ethereum/go-ethereum/issues/16106
|
|
|
|
if len(data) == 0 {
|
|
|
|
if txargs.Value.ToInt().Cmp(big.NewInt(0)) > 0 {
|
|
|
|
// Sending ether into black hole
|
2018-05-04 11:04:17 +03:00
|
|
|
return errors.New("Tx will create contract with value but empty code!")
|
cmd/clef, signer: initial poc of the standalone signer (#16154)
* signer: introduce external signer command
* cmd/signer, rpc: Implement new signer. Add info about remote user to Context
* signer: refactored request/response, made use of urfave.cli
* cmd/signer: Use common flags
* cmd/signer: methods to validate calldata against abi
* cmd/signer: work on abi parser
* signer: add mutex around UI
* cmd/signer: add json 4byte directory, remove passwords from api
* cmd/signer: minor changes
* cmd/signer: Use ErrRequestDenied, enable lightkdf
* cmd/signer: implement tests
* cmd/signer: made possible for UI to modify tx parameters
* cmd/signer: refactors, removed channels in ui comms, added UI-api via stdin/out
* cmd/signer: Made lowercase json-definitions, added UI-signer test functionality
* cmd/signer: update documentation
* cmd/signer: fix bugs, improve abi detection, abi argument display
* cmd/signer: minor change in json format
* cmd/signer: rework json communication
* cmd/signer: implement mixcase addresses in API, fix json id bug
* cmd/signer: rename fromaccount, update pythonpoc with new json encoding format
* cmd/signer: make use of new abi interface
* signer: documentation
* signer/main: remove redundant option
* signer: implement audit logging
* signer: create package 'signer', minor changes
* common: add 0x-prefix to mixcaseaddress in json marshalling + validation
* signer, rules, storage: implement rules + ephemeral storage for signer rules
* signer: implement OnApprovedTx, change signing response (API BREAKAGE)
* signer: refactoring + documentation
* signer/rules: implement dispatching to next handler
* signer: docs
* signer/rules: hide json-conversion from users, ensure context is cleaned
* signer: docs
* signer: implement validation rules, change signature of call_info
* signer: fix log flaw with string pointer
* signer: implement custom 4byte databsae that saves submitted signatures
* signer/storage: implement aes-gcm-backed credential storage
* accounts: implement json unmarshalling of url
* signer: fix listresponse, fix gas->uint64
* node: make http/ipc start methods public
* signer: add ipc capability+review concerns
* accounts: correct docstring
* signer: address review concerns
* rpc: go fmt -s
* signer: review concerns+ baptize Clef
* signer,node: move Start-functions to separate file
* signer: formatting
2018-04-16 15:04:32 +03:00
|
|
|
}
|
|
|
|
// No value submitted at least
|
|
|
|
msgs.crit("Tx will create contract with empty code!")
|
|
|
|
} else if len(data) < 40 { //Arbitrary limit
|
|
|
|
msgs.warn(fmt.Sprintf("Tx will will create contract, but payload is suspiciously small (%d b)", len(data)))
|
|
|
|
}
|
|
|
|
// methodSelector should be nil for contract creation
|
|
|
|
if methodSelector != nil {
|
|
|
|
msgs.warn("Tx will create contract, but method selector supplied; indicating intent to call a method.")
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if !txargs.To.ValidChecksum() {
|
|
|
|
msgs.warn("Invalid checksum on to-address")
|
|
|
|
}
|
|
|
|
// Normal transaction
|
|
|
|
if bytes.Equal(txargs.To.Address().Bytes(), common.Address{}.Bytes()) {
|
|
|
|
// Sending to 0
|
|
|
|
msgs.crit("Tx destination is the zero address!")
|
|
|
|
}
|
|
|
|
// Validate calldata
|
|
|
|
v.validateCallData(msgs, data, methodSelector)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ValidateTransaction does a number of checks on the supplied transaction, and returns either a list of warnings,
|
|
|
|
// or an error, indicating that the transaction should be immediately rejected
|
|
|
|
func (v *Validator) ValidateTransaction(txArgs *SendTxArgs, methodSelector *string) (*ValidationMessages, error) {
|
|
|
|
msgs := &ValidationMessages{}
|
|
|
|
return msgs, v.validate(msgs, txArgs, methodSelector)
|
|
|
|
}
|