all: add support for EIP-2718, EIP-2930 transactions (#21502)
This adds support for EIP-2718 typed transactions as well as EIP-2930 access list transactions (tx type 1). These EIPs are scheduled for the Berlin fork. There very few changes to existing APIs in core/types, and several new APIs to deal with access list transactions. In particular, there are two new constructor functions for transactions: types.NewTx and types.SignNewTx. Since the canonical encoding of typed transactions is not RLP-compatible, Transaction now has new methods for encoding and decoding: MarshalBinary and UnmarshalBinary. The existing EIP-155 signer does not support the new transaction types. All code dealing with transaction signatures should be updated to use the newer EIP-2930 signer. To make this easier for future updates, we have added new constructor functions for types.Signer: types.LatestSigner and types.LatestSignerForChainID. This change also adds support for the YoloV3 testnet. Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: Felix Lange <fjl@twurst.com> Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
This commit is contained in:
@ -120,7 +120,7 @@ func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accou
|
||||
if chainID == nil {
|
||||
return nil, ErrNoChainID
|
||||
}
|
||||
signer := types.NewEIP155Signer(chainID)
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
return &TransactOpts{
|
||||
From: account.Address,
|
||||
Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||
@ -143,7 +143,7 @@ func NewKeyedTransactorWithChainID(key *ecdsa.PrivateKey, chainID *big.Int) (*Tr
|
||||
if chainID == nil {
|
||||
return nil, ErrNoChainID
|
||||
}
|
||||
signer := types.NewEIP155Signer(chainID)
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
return &TransactOpts{
|
||||
From: keyAddr,
|
||||
Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||
|
@ -559,7 +559,10 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
sender, err := types.Sender(types.NewEIP155Signer(b.config.ChainID), tx)
|
||||
// Check transaction validity.
|
||||
block := b.blockchain.CurrentBlock()
|
||||
signer := types.MakeSigner(b.blockchain.Config(), block.Number())
|
||||
sender, err := types.Sender(signer, tx)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("invalid transaction: %v", err))
|
||||
}
|
||||
@ -568,7 +571,8 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
|
||||
}
|
||||
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
// Include tx in chain.
|
||||
blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
for _, tx := range b.pendingBlock.Transactions() {
|
||||
block.AddTxWithChain(b.blockchain, tx)
|
||||
}
|
||||
@ -707,14 +711,15 @@ type callMsg struct {
|
||||
ethereum.CallMsg
|
||||
}
|
||||
|
||||
func (m callMsg) From() common.Address { return m.CallMsg.From }
|
||||
func (m callMsg) Nonce() uint64 { return 0 }
|
||||
func (m callMsg) CheckNonce() bool { return false }
|
||||
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
||||
func (m callMsg) From() common.Address { return m.CallMsg.From }
|
||||
func (m callMsg) Nonce() uint64 { return 0 }
|
||||
func (m callMsg) CheckNonce() bool { return false }
|
||||
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
||||
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
|
||||
|
||||
// filterBackend implements filters.Backend to support filtering for logs without
|
||||
// taking bloom-bits acceleration structures into account.
|
||||
|
@ -283,11 +283,9 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b
|
||||
if !found {
|
||||
return nil, ErrLocked
|
||||
}
|
||||
// Depending on the presence of the chain ID, sign with EIP155 or homestead
|
||||
if chainID != nil {
|
||||
return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
|
||||
}
|
||||
return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)
|
||||
// Depending on the presence of the chain ID, sign with 2718 or homestead
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
return types.SignTx(tx, signer, unlockedKey.PrivateKey)
|
||||
}
|
||||
|
||||
// SignHashWithPassphrase signs hash if the private key matching the given address
|
||||
@ -310,12 +308,9 @@ func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string,
|
||||
return nil, err
|
||||
}
|
||||
defer zeroKey(key.PrivateKey)
|
||||
|
||||
// Depending on the presence of the chain ID, sign with EIP155 or homestead
|
||||
if chainID != nil {
|
||||
return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
|
||||
}
|
||||
return types.SignTx(tx, types.HomesteadSigner{}, key.PrivateKey)
|
||||
// Depending on the presence of the chain ID, sign with or without replay protection.
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
return types.SignTx(tx, signer, key.PrivateKey)
|
||||
}
|
||||
|
||||
// Unlock unlocks the given account indefinitely.
|
||||
|
@ -699,7 +699,7 @@ func (w *Wallet) signHash(account accounts.Account, hash []byte) ([]byte, error)
|
||||
// the needed details via SignTxWithPassphrase, or by other means (e.g. unlock
|
||||
// the account in a keystore).
|
||||
func (w *Wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
||||
signer := types.NewEIP155Signer(chainID)
|
||||
signer := types.LatestSignerForChainID(chainID)
|
||||
hash := signer.Hash(tx)
|
||||
sig, err := w.signHash(account, hash[:])
|
||||
if err != nil {
|
||||
|
@ -255,9 +255,11 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
|
||||
if chainID == nil {
|
||||
signer = new(types.HomesteadSigner)
|
||||
} else {
|
||||
// Trezor backend does not support typed transactions yet.
|
||||
signer = types.NewEIP155Signer(chainID)
|
||||
signature[64] -= byte(chainID.Uint64()*2 + 35)
|
||||
}
|
||||
|
||||
// Inject the final signature into the transaction and sanity check the sender
|
||||
signed, err := tx.WithSignature(signer, signature)
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user