// Note that this interface is not a stable API and may change at any time to accommodate // new protocol rules. type Signer interface { // 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) ChainID() *big.Int
// Hash returns 'signature hash', i.e. the transaction hash that is signed by the // private key. This hash does not uniquely identify the transaction. Hash(tx *Transaction) common.Hash
// Equal returns true if the given signer is the same as the receiver. Equal(Signer) bool }
type EIP155Signer struct { chainId, chainIdMul *big.Int } type eip2930Signer struct{ EIP155Signer } type londonSigner struct{ eip2930Signer }
创建新的 londonSigner 类型也可以看出来封装的特点:
1 2 3 4 5 6 7 8
// NewLondonSigner returns a signer that accepts // - EIP-1559 dynamic fee transactions // - EIP-2930 access list transactions, // - EIP-155 replay protected transactions, and // - legacy Homestead transactions. funcNewLondonSigner(chainId *big.Int) Signer { return londonSigner{eip2930Signer{NewEIP155Signer(chainId)}} }
Sender 的实现
1 2 3 4 5 6 7 8 9 10 11 12 13
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{}, ErrInvalidChainId } return recoverPlain(s.Hash(tx), R, S, V, true) }
先获取签名的三个参数,其中 V 的操作是 EIP-155 规定的防止重放的变化。恢复签名的核心参数是交易哈希和签名。注意这是过程中的交易哈希,并不是已经发送交易之后的哈希标识。
// 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 prefixedRlpHash( tx.Type(), []interface{}{ s.chainId, tx.Nonce(), tx.GasTipCap(), tx.GasFeeCap(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.AccessList(), }) }
可见,是交易的很多的参数综合生成的。
ecoverPlain 涉及到密码学,暂时不深入。
SignatureValues 的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
unc (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 { returnnil, nil, nil, ErrInvalidChainId } R, S, _ = decodeSignature(sig) V = big.NewInt(int64(sig[64])) return R, S, V, nil }
// MakeSigner returns a Signer based on the given chain config and block number. funcMakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { var signer Signer switch { case config.IsLondon(blockNumber): signer = NewLondonSigner(config.ChainID) case config.IsBerlin(blockNumber): signer = NewEIP2930Signer(config.ChainID) case config.IsEIP155(blockNumber): signer = NewEIP155Signer(config.ChainID) case config.IsHomestead(blockNumber): signer = HomesteadSigner{} default: signer = FrontierSigner{} } return signer }
// LatestSigner returns the 'most permissive' Signer available for the given chain // configuration. Specifically, this enables support of EIP-155 replay protection and // EIP-2930 access list transactions when their respective forks are scheduled to occur at // any block number in the chain config. // // Use this in transaction-handling code where the current block number is unknown. If you // have the current block number available, use MakeSigner instead. funcLatestSigner(config *params.ChainConfig) Signer { if config.ChainID != nil { if config.LondonBlock != nil { return NewLondonSigner(config.ChainID) } if config.BerlinBlock != nil { return NewEIP2930Signer(config.ChainID) } if config.EIP155Block != nil { return NewEIP155Signer(config.ChainID) } } return HomesteadSigner{} }
// LatestSignerForChainID returns the 'most permissive' Signer available. Specifically, // this enables support for EIP-155 replay protection and all implemented EIP-2718 // transaction types if chainID is non-nil. // // Use this in transaction-handling code where the current block number and fork // configuration are unknown. If you have a ChainConfig, use LatestSigner instead. // If you have a ChainConfig and know the current block number, use MakeSigner instead. funcLatestSignerForChainID(chainID *big.Int) Signer { if chainID == nil { return HomesteadSigner{} } return NewLondonSigner(chainID) }
交易的签名
源码中设置了两种签名方式:
交易+签名器+私钥
1 2 3 4 5 6 7 8 9
// SignTx signs the transaction using the given signer and private key. funcSignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) { h := s.Hash(tx) sig, err := crypto.Sign(h[:], prv) if err != nil { returnnil, err } return tx.WithSignature(s, sig) }
原始交易数据+签名器+私钥
1 2 3 4 5 6 7 8 9 10
// SignNewTx creates a transaction and signs it. funcSignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) (*Transaction, error) { tx := NewTx(txdata) h := s.Hash(tx) sig, err := crypto.Sign(h[:], prv) if err != nil { returnnil, err } return tx.WithSignature(s, sig) }