aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/types/transaction.go14
-rw-r--r--core/types/transaction_signing.go174
-rw-r--r--core/types/transaction_test.go5
-rw-r--r--ethclient/ethclient.go85
-rw-r--r--ethclient/signer.go59
-rw-r--r--mobile/ethclient.go7
-rw-r--r--mobile/types.go9
7 files changed, 204 insertions, 149 deletions
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 7f54860fc..a46521236 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -209,12 +209,6 @@ func (tx *Transaction) Hash() common.Hash {
return v
}
-// SigHash returns the hash to be signed by the sender.
-// It does not uniquely identify the transaction.
-func (tx *Transaction) SigHash(signer Signer) common.Hash {
- return signer.Hash(tx)
-}
-
func (tx *Transaction) Size() common.StorageSize {
if size := tx.size.Load(); size != nil {
return size.(common.StorageSize)
@@ -249,7 +243,13 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
- return signer.WithSignature(tx, sig)
+ r, s, v, err := signer.SignatureValues(tx, sig)
+ if err != nil {
+ return nil, err
+ }
+ cpy := &Transaction{data: tx.data}
+ cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
+ return cpy, nil
}
// Cost returns amount + gasprice * gaslimit.
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
index ba4f2aa03..dfc84fdac 100644
--- a/core/types/transaction_signing.go
+++ b/core/types/transaction_signing.go
@@ -29,9 +29,6 @@ import (
var (
ErrInvalidChainId = errors.New("invalid chain id for signer")
-
- errAbstractSigner = errors.New("abstract signer")
- abstractSignerAddress = common.HexToAddress("ffffffffffffffffffffffffffffffffffffffff")
)
// sigCache is used to cache the derived sender and contains
@@ -62,12 +59,9 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err
if err != nil {
return nil, err
}
- return s.WithSignature(tx, sig)
+ return tx.WithSignature(s, sig)
}
-// Sender derives the sender from the tx using the signer derivation
-// functions.
-
// Sender returns the address derived from the signature (V, R, S) using secp256k1
// elliptic curve and an error if it failed deriving or upon an incorrect
// signature.
@@ -86,33 +80,30 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
}
}
- pubkey, err := signer.PublicKey(tx)
+ addr, err := signer.Sender(tx)
if err != nil {
return common.Address{}, err
}
- var addr common.Address
- copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
tx.from.Store(sigCache{signer: signer, from: addr})
return addr, nil
}
+// Signer encapsulates transaction signature handling. Note that this interface is not a
+// stable API and may change at any time to accommodate new protocol rules.
type Signer interface {
- // Hash returns the rlp encoded hash for signatures
+ // Sender returns the sender address of the transaction.
+ Sender(tx *Transaction) (common.Address, error)
+ // SignatureValues returns the raw R, S, V values corresponding to the
+ // given signature.
+ SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
+ // Hash returns the hash to be signed.
Hash(tx *Transaction) common.Hash
- // PubilcKey returns the public key derived from the signature
- PublicKey(tx *Transaction) ([]byte, error)
- // WithSignature returns a copy of the transaction with the given signature.
- // The signature must be encoded in [R || S || V] format where V is 0 or 1.
- WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
- // Checks for equality on the signers
+ // Equal returns true if the given signer is the same as the receiver.
Equal(Signer) bool
}
-// EIP155Transaction implements TransactionInterface using the
-// EIP155 rules
+// EIP155Transaction implements Signer using the EIP155 rules.
type EIP155Signer struct {
- HomesteadSigner
-
chainId, chainIdMul *big.Int
}
@@ -131,55 +122,32 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
return ok && eip155.chainId.Cmp(s.chainId) == 0
}
-func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
- // if the transaction is not protected fall back to homestead signer
+var big8 = big.NewInt(8)
+
+func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
if !tx.Protected() {
- return (HomesteadSigner{}).PublicKey(tx)
+ return HomesteadSigner{}.Sender(tx)
}
-
if tx.ChainId().Cmp(s.chainId) != 0 {
- return nil, ErrInvalidChainId
- }
-
- V := byte(new(big.Int).Sub(tx.data.V, s.chainIdMul).Uint64() - 35)
- if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
- return nil, ErrInvalidSig
- }
- // encode the signature in uncompressed format
- R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
- sig := make([]byte, 65)
- copy(sig[32-len(R):32], R)
- copy(sig[64-len(S):64], S)
- sig[64] = V
-
- // recover the public key from the signature
- hash := s.Hash(tx)
- pub, err := crypto.Ecrecover(hash[:], sig)
- if err != nil {
- return nil, err
- }
- if len(pub) == 0 || pub[0] != 4 {
- return nil, errors.New("invalid public key")
+ return common.Address{}, ErrInvalidChainId
}
- return pub, nil
+ V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
+ V.Sub(V, big8)
+ return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
}
// WithSignature returns a new transaction with the given signature. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
-func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
- if len(sig) != 65 {
- panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
+func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
+ R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
+ if err != nil {
+ return nil, nil, nil, err
}
-
- cpy := &Transaction{data: tx.data}
- cpy.data.R = new(big.Int).SetBytes(sig[:32])
- cpy.data.S = new(big.Int).SetBytes(sig[32:64])
- cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
if s.chainId.Sign() != 0 {
- cpy.data.V = big.NewInt(int64(sig[64] + 35))
- cpy.data.V.Add(cpy.data.V, s.chainIdMul)
+ V = big.NewInt(int64(sig[64] + 35))
+ V.Add(V, s.chainIdMul)
}
- return cpy, nil
+ return R, S, V, nil
}
// Hash returns the hash to be signed by the sender.
@@ -205,44 +173,14 @@ func (s HomesteadSigner) Equal(s2 Signer) bool {
return ok
}
-// WithSignature returns a new transaction with the given signature. This signature
+// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
-func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
- if len(sig) != 65 {
- panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
- }
- cpy := &Transaction{data: tx.data}
- cpy.data.R = new(big.Int).SetBytes(sig[:32])
- cpy.data.S = new(big.Int).SetBytes(sig[32:64])
- cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
- return cpy, nil
+func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
+ return hs.FrontierSigner.SignatureValues(tx, sig)
}
-func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
- if tx.data.V.BitLen() > 8 {
- return nil, ErrInvalidSig
- }
- V := byte(tx.data.V.Uint64() - 27)
- if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
- return nil, ErrInvalidSig
- }
- // encode the snature in uncompressed format
- r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
- sig := make([]byte, 65)
- copy(sig[32-len(r):32], r)
- copy(sig[64-len(s):64], s)
- sig[64] = V
-
- // recover the public key from the snature
- hash := hs.Hash(tx)
- pub, err := crypto.Ecrecover(hash[:], sig)
- if err != nil {
- return nil, err
- }
- if len(pub) == 0 || pub[0] != 4 {
- return nil, errors.New("invalid public key")
- }
- return pub, nil
+func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
+ return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
}
type FrontierSigner struct{}
@@ -252,20 +190,19 @@ func (s FrontierSigner) Equal(s2 Signer) bool {
return ok
}
-// WithSignature returns a new transaction with the given signature. This signature
+// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
-func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
+func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
if len(sig) != 65 {
- panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
+ panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
}
- cpy := &Transaction{data: tx.data}
- cpy.data.R = new(big.Int).SetBytes(sig[:32])
- cpy.data.S = new(big.Int).SetBytes(sig[32:64])
- cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
- return cpy, nil
+ r = new(big.Int).SetBytes(sig[:32])
+ s = new(big.Int).SetBytes(sig[32:64])
+ v = new(big.Int).SetBytes([]byte{sig[64] + 27})
+ return r, s, v, nil
}
-// Hash returns the hash to be sned by the sender.
+// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
return rlpHash([]interface{}{
@@ -278,32 +215,35 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
})
}
-func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
- if tx.data.V.BitLen() > 8 {
- return nil, ErrInvalidSig
- }
+func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
+ return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
+}
- V := byte(tx.data.V.Uint64() - 27)
- if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
- return nil, ErrInvalidSig
+func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
+ if Vb.BitLen() > 8 {
+ return common.Address{}, ErrInvalidSig
+ }
+ V := byte(Vb.Uint64() - 27)
+ if !crypto.ValidateSignatureValues(V, R, S, homestead) {
+ return common.Address{}, ErrInvalidSig
}
// encode the snature in uncompressed format
- r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
+ r, s := R.Bytes(), S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = V
-
// recover the public key from the snature
- hash := fs.Hash(tx)
- pub, err := crypto.Ecrecover(hash[:], sig)
+ pub, err := crypto.Ecrecover(sighash[:], sig)
if err != nil {
- return nil, err
+ return common.Address{}, err
}
if len(pub) == 0 || pub[0] != 4 {
- return nil, errors.New("invalid public key")
+ return common.Address{}, errors.New("invalid public key")
}
- return pub, nil
+ var addr common.Address
+ copy(addr[:], crypto.Keccak256(pub[1:])[12:])
+ return addr, nil
}
// deriveChainId derives the chain id from the given v parameter
diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go
index df9d7ffd1..30ecb84dd 100644
--- a/core/types/transaction_test.go
+++ b/core/types/transaction_test.go
@@ -52,10 +52,11 @@ var (
)
func TestTransactionSigHash(t *testing.T) {
- if emptyTx.SigHash(HomesteadSigner{}) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
+ var homestead HomesteadSigner
+ if homestead.Hash(emptyTx) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash())
}
- if rightvrsTx.SigHash(HomesteadSigner{}) != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
+ if homestead.Hash(rightvrsTx) != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash())
}
}
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index 48639d949..7f73ab113 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -20,6 +20,7 @@ package ethclient
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"math/big"
@@ -70,9 +71,9 @@ func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Bl
}
type rpcBlock struct {
- Hash common.Hash `json:"hash"`
- Transactions []*types.Transaction `json:"transactions"`
- UncleHashes []common.Hash `json:"uncles"`
+ Hash common.Hash `json:"hash"`
+ Transactions []rpcTransaction `json:"transactions"`
+ UncleHashes []common.Hash `json:"uncles"`
}
func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) {
@@ -129,7 +130,13 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
}
}
}
- return types.NewBlockWithHeader(head).WithBody(body.Transactions, uncles), nil
+ // Fill the sender cache of transactions in the block.
+ txs := make([]*types.Transaction, len(body.Transactions))
+ for i, tx := range body.Transactions {
+ setSenderFromServer(tx.tx, tx.From, body.Hash)
+ txs[i] = tx.tx
+ }
+ return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil
}
// HeaderByHash returns the block header with the given hash.
@@ -153,25 +160,62 @@ func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H
return head, err
}
+type rpcTransaction struct {
+ tx *types.Transaction
+ txExtraInfo
+}
+
+type txExtraInfo struct {
+ BlockNumber *string
+ BlockHash common.Hash
+ From common.Address
+}
+
+func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
+ if err := json.Unmarshal(msg, &tx.tx); err != nil {
+ return err
+ }
+ return json.Unmarshal(msg, &tx.txExtraInfo)
+}
+
// TransactionByHash returns the transaction with the given hash.
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
- var raw json.RawMessage
- err = ec.c.CallContext(ctx, &raw, "eth_getTransactionByHash", hash)
+ var json *rpcTransaction
+ err = ec.c.CallContext(ctx, &json, "eth_getTransactionByHash", hash)
if err != nil {
return nil, false, err
- } else if len(raw) == 0 {
+ } else if json == nil {
return nil, false, ethereum.NotFound
- }
- if err := json.Unmarshal(raw, &tx); err != nil {
- return nil, false, err
- } else if _, r, _ := tx.RawSignatureValues(); r == nil {
+ } else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
return nil, false, fmt.Errorf("server returned transaction without signature")
}
- var block struct{ BlockNumber *string }
- if err := json.Unmarshal(raw, &block); err != nil {
- return nil, false, err
+ setSenderFromServer(json.tx, json.From, json.BlockHash)
+ return json.tx, json.BlockNumber == nil, nil
+}
+
+// TransactionSender returns the sender address of the given transaction. The transaction
+// must be known to the remote node and included in the blockchain at the given block and
+// index. The sender is the one derived by the protocol at the time of inclusion.
+//
+// There is a fast-path for transactions retrieved by TransactionByHash and
+// TransactionInBlock. Getting their sender address can be done without an RPC interaction.
+func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
+ // Try to load the address from the cache.
+ sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
+ if err == nil {
+ return sender, nil
+ }
+ var meta struct {
+ Hash common.Hash
+ From common.Address
+ }
+ if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
+ return common.Address{}, err
+ }
+ if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
+ return common.Address{}, errors.New("wrong inclusion block/index")
}
- return tx, block.BlockNumber == nil, nil
+ return meta.From, nil
}
// TransactionCount returns the total number of transactions in the given block.
@@ -183,16 +227,17 @@ func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (
// TransactionInBlock returns a single transaction at index in the given block.
func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
- var tx *types.Transaction
- err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
+ var json *rpcTransaction
+ err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
if err == nil {
- if tx == nil {
+ if json == nil {
return nil, ethereum.NotFound
- } else if _, r, _ := tx.RawSignatureValues(); r == nil {
+ } else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
return nil, fmt.Errorf("server returned transaction without signature")
}
}
- return tx, err
+ setSenderFromServer(json.tx, json.From, json.BlockHash)
+ return json.tx, err
}
// TransactionReceipt returns the receipt of a transaction by transaction hash.
diff --git a/ethclient/signer.go b/ethclient/signer.go
new file mode 100644
index 000000000..74a93f1e2
--- /dev/null
+++ b/ethclient/signer.go
@@ -0,0 +1,59 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ethclient
+
+import (
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+// senderFromServer is a types.Signer that remembers the sender address returned by the RPC
+// server. It is stored in the transaction's sender address cache to avoid an additional
+// request in TransactionSender.
+type senderFromServer struct {
+ addr common.Address
+ blockhash common.Hash
+}
+
+var errNotCached = errors.New("sender not cached")
+
+func setSenderFromServer(tx *types.Transaction, addr common.Address, block common.Hash) {
+ // Use types.Sender for side-effect to store our signer into the cache.
+ types.Sender(&senderFromServer{addr, block}, tx)
+}
+
+func (s *senderFromServer) Equal(other types.Signer) bool {
+ os, ok := other.(*senderFromServer)
+ return ok && os.blockhash == s.blockhash
+}
+
+func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error) {
+ if s.blockhash == (common.Hash{}) {
+ return common.Address{}, errNotCached
+ }
+ return s.addr, nil
+}
+
+func (s *senderFromServer) Hash(tx *types.Transaction) common.Hash {
+ panic("can't sign with senderFromServer")
+}
+func (s *senderFromServer) SignatureValues(tx *types.Transaction, sig []byte) (R, S, V *big.Int, err error) {
+ panic("can't sign with senderFromServer")
+}
diff --git a/mobile/ethclient.go b/mobile/ethclient.go
index 4e8328501..7f31a8998 100644
--- a/mobile/ethclient.go
+++ b/mobile/ethclient.go
@@ -77,6 +77,13 @@ func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (tx *Tr
return &Transaction{rawTx}, err
}
+// GetTransactionSender returns the sender address of a transaction. The transaction must
+// be included in blockchain at the given block and index.
+func (ec *EthereumClient) GetTransactionSender(ctx *Context, tx *Transaction, blockhash *Hash, index int) (sender *Address, _ error) {
+ addr, err := ec.client.TransactionSender(ctx.context, tx.tx, blockhash.hash, uint(index))
+ return &Address{addr}, err
+}
+
// GetTransactionCount returns the total number of transactions in the given block.
func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count int, _ error) {
rawCount, err := ec.client.TransactionCount(ctx.context, hash.hash)
diff --git a/mobile/types.go b/mobile/types.go
index 088c7c6b3..b7f8a3bc1 100644
--- a/mobile/types.go
+++ b/mobile/types.go
@@ -261,10 +261,13 @@ func (tx *Transaction) GetGasPrice() *BigInt { return &BigInt{tx.tx.GasPrice()}
func (tx *Transaction) GetValue() *BigInt { return &BigInt{tx.tx.Value()} }
func (tx *Transaction) GetNonce() int64 { return int64(tx.tx.Nonce()) }
-func (tx *Transaction) GetHash() *Hash { return &Hash{tx.tx.Hash()} }
-func (tx *Transaction) GetSigHash() *Hash { return &Hash{tx.tx.SigHash(types.HomesteadSigner{})} }
-func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} }
+func (tx *Transaction) GetHash() *Hash { return &Hash{tx.tx.Hash()} }
+func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} }
+// Deprecated: GetSigHash cannot know which signer to use.
+func (tx *Transaction) GetSigHash() *Hash { return &Hash{types.HomesteadSigner{}.Hash(tx.tx)} }
+
+// Deprecated: use EthereumClient.TransactionSender
func (tx *Transaction) GetFrom(chainID *BigInt) (address *Address, _ error) {
var signer types.Signer = types.HomesteadSigner{}
if chainID != nil {