mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-17 21:46:36 +00:00
core/types: cleanup tx signer logic (#31434)
This removes the signer type-train in favor of defining a single object that can handle all tx types. Supported types are enabled via a map. Notably, the new signer also supports disabling legacy transactions.
This commit is contained in:
parent
b47e4d5b38
commit
80b8d7a13c
3 changed files with 110 additions and 211 deletions
|
|
@ -102,7 +102,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran
|
||||||
if tx.protected {
|
if tx.protected {
|
||||||
signed, err = types.SignTx(tx.tx, signer, tx.key)
|
signed, err = types.SignTx(tx.tx, signer, tx.key)
|
||||||
} else {
|
} else {
|
||||||
signed, err = types.SignTx(tx.tx, types.FrontierSigner{}, tx.key)
|
signed, err = types.SignTx(tx.tx, types.HomesteadSigner{}, tx.key)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err))
|
return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err))
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrInvalidChainId = errors.New("invalid chain id for signer")
|
var ErrInvalidChainId = errors.New("invalid chain id for signer")
|
||||||
|
|
@ -178,7 +180,101 @@ type Signer interface {
|
||||||
Equal(Signer) bool
|
Equal(Signer) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type pragueSigner struct{ cancunSigner }
|
// modernSigner is the signer implementation that handles non-legacy transaction types.
|
||||||
|
// For legacy transactions, it defers to one of the legacy signers (frontier, homestead, eip155).
|
||||||
|
type modernSigner struct {
|
||||||
|
txtypes map[byte]struct{}
|
||||||
|
chainID *big.Int
|
||||||
|
legacy Signer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
|
||||||
|
if chainID == nil || chainID.Sign() <= 0 {
|
||||||
|
panic(fmt.Sprintf("invalid chainID %v", chainID))
|
||||||
|
}
|
||||||
|
s := &modernSigner{
|
||||||
|
chainID: chainID,
|
||||||
|
txtypes: make(map[byte]struct{}, 4),
|
||||||
|
}
|
||||||
|
// configure legacy signer
|
||||||
|
switch {
|
||||||
|
case fork >= forks.SpuriousDragon:
|
||||||
|
s.legacy = NewEIP155Signer(chainID)
|
||||||
|
case fork >= forks.Homestead:
|
||||||
|
s.legacy = HomesteadSigner{}
|
||||||
|
default:
|
||||||
|
s.legacy = FrontierSigner{}
|
||||||
|
}
|
||||||
|
s.txtypes[LegacyTxType] = struct{}{}
|
||||||
|
// configure tx types
|
||||||
|
if fork >= forks.Berlin {
|
||||||
|
s.txtypes[AccessListTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
if fork >= forks.London {
|
||||||
|
s.txtypes[DynamicFeeTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
if fork >= forks.Cancun {
|
||||||
|
s.txtypes[BlobTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
if fork >= forks.Prague {
|
||||||
|
s.txtypes[SetCodeTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) ChainID() *big.Int {
|
||||||
|
return s.chainID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) Equal(s2 Signer) bool {
|
||||||
|
other, ok := s2.(*modernSigner)
|
||||||
|
return ok && s.chainID.Cmp(other.chainID) == 0 && maps.Equal(s.txtypes, other.txtypes) && s.legacy.Equal(other.legacy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) Hash(tx *Transaction) common.Hash {
|
||||||
|
return tx.inner.sigHash(s.chainID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) supportsType(txtype byte) bool {
|
||||||
|
_, ok := s.txtypes[txtype]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) Sender(tx *Transaction) (common.Address, error) {
|
||||||
|
tt := tx.Type()
|
||||||
|
if !s.supportsType(tt) {
|
||||||
|
return common.Address{}, ErrTxTypeNotSupported
|
||||||
|
}
|
||||||
|
if tt == LegacyTxType {
|
||||||
|
return s.legacy.Sender(tx)
|
||||||
|
}
|
||||||
|
if tx.ChainId().Cmp(s.chainID) != 0 {
|
||||||
|
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainID)
|
||||||
|
}
|
||||||
|
// 'modern' txs are defined to use 0 and 1 as their recovery
|
||||||
|
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
||||||
|
V, R, S := tx.RawSignatureValues()
|
||||||
|
V = new(big.Int).Add(V, big.NewInt(27))
|
||||||
|
return recoverPlain(s.Hash(tx), R, S, V, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
||||||
|
tt := tx.Type()
|
||||||
|
if !s.supportsType(tt) {
|
||||||
|
return nil, nil, nil, ErrTxTypeNotSupported
|
||||||
|
}
|
||||||
|
if tt == LegacyTxType {
|
||||||
|
return s.legacy.SignatureValues(tx, sig)
|
||||||
|
}
|
||||||
|
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
||||||
|
// because it indicates that the chain ID was not specified in the tx.
|
||||||
|
if tx.inner.chainID().Sign() != 0 && tx.inner.chainID().Cmp(s.chainID) != 0 {
|
||||||
|
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.inner.chainID(), s.chainID)
|
||||||
|
}
|
||||||
|
R, S, _ = decodeSignature(sig)
|
||||||
|
V = big.NewInt(int64(sig[64]))
|
||||||
|
return R, S, V, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewPragueSigner returns a signer that accepts
|
// NewPragueSigner returns a signer that accepts
|
||||||
// - EIP-7702 set code transactions
|
// - EIP-7702 set code transactions
|
||||||
|
|
@ -188,56 +284,9 @@ type pragueSigner struct{ cancunSigner }
|
||||||
// - EIP-155 replay protected transactions, and
|
// - EIP-155 replay protected transactions, and
|
||||||
// - legacy Homestead transactions.
|
// - legacy Homestead transactions.
|
||||||
func NewPragueSigner(chainId *big.Int) Signer {
|
func NewPragueSigner(chainId *big.Int) Signer {
|
||||||
signer, _ := NewCancunSigner(chainId).(cancunSigner)
|
return newModernSigner(chainId, forks.Prague)
|
||||||
return pragueSigner{signer}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s pragueSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
if tx.Type() != SetCodeTxType {
|
|
||||||
return s.cancunSigner.Sender(tx)
|
|
||||||
}
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
|
|
||||||
// Set code txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s pragueSigner) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(pragueSigner)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
txdata, ok := tx.inner.(*SetCodeTx)
|
|
||||||
if !ok {
|
|
||||||
return s.cancunSigner.SignatureValues(tx, sig)
|
|
||||||
}
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s pragueSigner) Hash(tx *Transaction) common.Hash {
|
|
||||||
if tx.Type() != SetCodeTxType {
|
|
||||||
return s.cancunSigner.Hash(tx)
|
|
||||||
}
|
|
||||||
return tx.inner.sigHash(s.chainId)
|
|
||||||
}
|
|
||||||
|
|
||||||
type cancunSigner struct{ londonSigner }
|
|
||||||
|
|
||||||
// NewCancunSigner returns a signer that accepts
|
// NewCancunSigner returns a signer that accepts
|
||||||
// - EIP-4844 blob transactions
|
// - EIP-4844 blob transactions
|
||||||
// - EIP-1559 dynamic fee transactions
|
// - EIP-1559 dynamic fee transactions
|
||||||
|
|
@ -245,178 +294,27 @@ type cancunSigner struct{ londonSigner }
|
||||||
// - EIP-155 replay protected transactions, and
|
// - EIP-155 replay protected transactions, and
|
||||||
// - legacy Homestead transactions.
|
// - legacy Homestead transactions.
|
||||||
func NewCancunSigner(chainId *big.Int) Signer {
|
func NewCancunSigner(chainId *big.Int) Signer {
|
||||||
return cancunSigner{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}}
|
return newModernSigner(chainId, forks.Cancun)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s cancunSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
if tx.Type() != BlobTxType {
|
|
||||||
return s.londonSigner.Sender(tx)
|
|
||||||
}
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
// Blob txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s cancunSigner) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(cancunSigner)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s cancunSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
txdata, ok := tx.inner.(*BlobTx)
|
|
||||||
if !ok {
|
|
||||||
return s.londonSigner.SignatureValues(tx, sig)
|
|
||||||
}
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s cancunSigner) Hash(tx *Transaction) common.Hash {
|
|
||||||
if tx.Type() != BlobTxType {
|
|
||||||
return s.londonSigner.Hash(tx)
|
|
||||||
}
|
|
||||||
return tx.inner.sigHash(s.chainId)
|
|
||||||
}
|
|
||||||
|
|
||||||
type londonSigner struct{ eip2930Signer }
|
|
||||||
|
|
||||||
// NewLondonSigner returns a signer that accepts
|
// NewLondonSigner returns a signer that accepts
|
||||||
// - EIP-1559 dynamic fee transactions
|
// - EIP-1559 dynamic fee transactions
|
||||||
// - EIP-2930 access list transactions,
|
// - EIP-2930 access list transactions,
|
||||||
// - EIP-155 replay protected transactions, and
|
// - EIP-155 replay protected transactions, and
|
||||||
// - legacy Homestead transactions.
|
// - legacy Homestead transactions.
|
||||||
func NewLondonSigner(chainId *big.Int) Signer {
|
func NewLondonSigner(chainId *big.Int) Signer {
|
||||||
return londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}
|
return newModernSigner(chainId, forks.London)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s londonSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
if tx.Type() != DynamicFeeTxType {
|
|
||||||
return s.eip2930Signer.Sender(tx)
|
|
||||||
}
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
// DynamicFee txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s londonSigner) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(londonSigner)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
txdata, ok := tx.inner.(*DynamicFeeTx)
|
|
||||||
if !ok {
|
|
||||||
return s.eip2930Signer.SignatureValues(tx, sig)
|
|
||||||
}
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s londonSigner) Hash(tx *Transaction) common.Hash {
|
|
||||||
if tx.Type() != DynamicFeeTxType {
|
|
||||||
return s.eip2930Signer.Hash(tx)
|
|
||||||
}
|
|
||||||
return tx.inner.sigHash(s.chainId)
|
|
||||||
}
|
|
||||||
|
|
||||||
type eip2930Signer struct{ EIP155Signer }
|
|
||||||
|
|
||||||
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
|
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
|
||||||
// EIP-155 replay protected transactions, and legacy Homestead transactions.
|
// EIP-155 replay protected transactions, and legacy Homestead transactions.
|
||||||
func NewEIP2930Signer(chainId *big.Int) Signer {
|
func NewEIP2930Signer(chainId *big.Int) Signer {
|
||||||
return eip2930Signer{NewEIP155Signer(chainId)}
|
return newModernSigner(chainId, forks.Berlin)
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) ChainID() *big.Int {
|
|
||||||
return s.chainId
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(eip2930Signer)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
switch tx.Type() {
|
|
||||||
case LegacyTxType:
|
|
||||||
return s.EIP155Signer.Sender(tx)
|
|
||||||
case AccessListTxType:
|
|
||||||
// AL txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
default:
|
|
||||||
return common.Address{}, ErrTxTypeNotSupported
|
|
||||||
}
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
switch txdata := tx.inner.(type) {
|
|
||||||
case *LegacyTx:
|
|
||||||
return s.EIP155Signer.SignatureValues(tx, sig)
|
|
||||||
case *AccessListTx:
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
default:
|
|
||||||
return nil, nil, nil, ErrTxTypeNotSupported
|
|
||||||
}
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s eip2930Signer) Hash(tx *Transaction) common.Hash {
|
|
||||||
switch tx.Type() {
|
|
||||||
case LegacyTxType:
|
|
||||||
return s.EIP155Signer.Hash(tx)
|
|
||||||
case AccessListTxType:
|
|
||||||
return tx.inner.sigHash(s.chainId)
|
|
||||||
default:
|
|
||||||
// This _should_ not happen, but in case someone sends in a bad
|
|
||||||
// json struct via RPC, it's probably more prudent to return an
|
|
||||||
// empty hash instead of killing the node with a panic
|
|
||||||
//panic("Unsupported transaction type: %d", tx.typ)
|
|
||||||
return common.Hash{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which
|
// EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which
|
||||||
// are replay-protected as well as unprotected homestead transactions.
|
// are replay-protected as well as unprotected homestead transactions.
|
||||||
|
// Deprecated: always use the Signer interface type
|
||||||
type EIP155Signer struct {
|
type EIP155Signer struct {
|
||||||
chainId, chainIdMul *big.Int
|
chainId, chainIdMul *big.Int
|
||||||
}
|
}
|
||||||
|
|
@ -478,8 +376,9 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
||||||
return tx.inner.sigHash(s.chainId)
|
return tx.inner.sigHash(s.chainId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HomesteadSigner implements Signer interface using the
|
// HomesteadSigner implements Signer using the homestead rules. The only valid reason to
|
||||||
// homestead rules.
|
// use this type is creating legacy transactions which are intentionally not
|
||||||
|
// replay-protected.
|
||||||
type HomesteadSigner struct{ FrontierSigner }
|
type HomesteadSigner struct{ FrontierSigner }
|
||||||
|
|
||||||
func (hs HomesteadSigner) ChainID() *big.Int {
|
func (hs HomesteadSigner) ChainID() *big.Int {
|
||||||
|
|
@ -505,8 +404,8 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
|
||||||
return recoverPlain(hs.Hash(tx), r, s, v, true)
|
return recoverPlain(hs.Hash(tx), r, s, v, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrontierSigner implements Signer interface using the
|
// FrontierSigner implements Signer using the frontier rules.
|
||||||
// frontier rules.
|
// Deprecated: always use the Signer interface type
|
||||||
type FrontierSigner struct{}
|
type FrontierSigner struct{}
|
||||||
|
|
||||||
func (fs FrontierSigner) ChainID() *big.Int {
|
func (fs FrontierSigner) ChainID() *big.Int {
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ const (
|
||||||
FrontierThawing
|
FrontierThawing
|
||||||
Homestead
|
Homestead
|
||||||
DAO
|
DAO
|
||||||
TangerineWhistle
|
TangerineWhistle // a.k.a. the EIP150 fork
|
||||||
SpuriousDragon
|
SpuriousDragon // a.k.a. the EIP155 fork
|
||||||
Byzantium
|
Byzantium
|
||||||
Constantinople
|
Constantinople
|
||||||
Petersburg
|
Petersburg
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue