Igor Mandrigin a9eb5a7d2b Generalize signing requests.
We need to be able to sign more than just transactions to make DApps
work properly. This change separates signing requests from the
transactions and make it more general to prepare to intoduce different
types of signing requests.

This change is designed to preserve status APIs, so it is
backward-comparible with the current API bindings.
2018-04-09 20:48:00 +02:00

89 lines
2.6 KiB
Go

package transactions
import (
"bytes"
"context"
"encoding/json"
"errors"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var (
// ErrInvalidSendTxArgs is returned when the structure of SendTxArgs is ambigious.
ErrInvalidSendTxArgs = errors.New("Transaction arguments are invalid (are both 'input' and 'data' fields used?)")
// ErrUnexpectedArgs returned when args are of unexpected length.
ErrUnexpectedArgs = errors.New("unexpected args")
)
// PendingNonceProvider provides information about nonces.
type PendingNonceProvider interface {
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
}
// GasCalculator provides methods for estimating and pricing gas.
type GasCalculator interface {
ethereum.GasEstimator
ethereum.GasPricer
}
// SendTxArgs represents the arguments to submit a new transaction into the transaction pool.
// This struct is based on go-ethereum's type in internal/ethapi/api.go, but we have freedom
// over the exact layout of this struct.
type SendTxArgs struct {
From common.Address `json:"from"`
To *common.Address `json:"to"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
// We keep both "input" and "data" for backward compatibility.
// "input" is a preferred field.
// see `vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go:1107`
Input hexutil.Bytes `json:"input"`
Data hexutil.Bytes `json:"data"`
}
// Valid checks whether this structure is filled in correctly.
func (args SendTxArgs) Valid() bool {
// if at least one of the fields is empty, it is a valid struct
if isNilOrEmpty(args.Input) || isNilOrEmpty(args.Data) {
return true
}
// we only allow both fields to present if they have the same data
return bytes.Equal(args.Input, args.Data)
}
// GetInput returns either Input or Data field's value dependent on what is filled.
func (args SendTxArgs) GetInput() hexutil.Bytes {
if !isNilOrEmpty(args.Input) {
return args.Input
}
return args.Data
}
func isNilOrEmpty(bytes hexutil.Bytes) bool {
return bytes == nil || len(bytes) == 0
}
// RPCCalltoSendTxArgs creates SendTxArgs based on RPC parameters
func RPCCalltoSendTxArgs(args ...interface{}) (SendTxArgs, error) {
var txArgs SendTxArgs
if len(args) != 1 {
return txArgs, ErrUnexpectedArgs
}
data, err := json.Marshal(args[0])
if err != nil {
return txArgs, err
}
if err := json.Unmarshal(data, &txArgs); err != nil {
return txArgs, err
}
return txArgs, nil
}