mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
Preserve set-code auth list in external signer
This commit is contained in:
parent
e3b6d0c86f
commit
47622451dc
4 changed files with 197 additions and 7 deletions
26
accounts/external/backend.go
vendored
26
accounts/external/backend.go
vendored
|
|
@ -198,6 +198,19 @@ type signTransactionResult struct {
|
||||||
// by the external signer. For non-legacy transactions, the chain ID of the
|
// by the external signer. For non-legacy transactions, the chain ID of the
|
||||||
// transaction overrides the chainID parameter.
|
// transaction overrides the chainID parameter.
|
||||||
func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
||||||
|
args, err := signTxArgs(account, tx, chainID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res signTransactionResult
|
||||||
|
if err := api.client.Call(&res, "account_signTransaction", args); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func signTxArgs(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*apitypes.SendTxArgs, error) {
|
||||||
data := hexutil.Bytes(tx.Data())
|
data := hexutil.Bytes(tx.Data())
|
||||||
var to *common.MixedcaseAddress
|
var to *common.MixedcaseAddress
|
||||||
if tx.To() != nil {
|
if tx.To() != nil {
|
||||||
|
|
@ -215,9 +228,13 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||||
switch tx.Type() {
|
switch tx.Type() {
|
||||||
case types.LegacyTxType, types.AccessListTxType:
|
case types.LegacyTxType, types.AccessListTxType:
|
||||||
args.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
args.GasPrice = (*hexutil.Big)(tx.GasPrice())
|
||||||
case types.DynamicFeeTxType, types.BlobTxType, types.SetCodeTxType:
|
case types.DynamicFeeTxType, types.BlobTxType:
|
||||||
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
case types.SetCodeTxType:
|
||||||
|
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
|
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
args.AuthorizationList = tx.SetCodeAuthorizations()
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported tx type %d", tx.Type())
|
return nil, fmt.Errorf("unsupported tx type %d", tx.Type())
|
||||||
}
|
}
|
||||||
|
|
@ -246,12 +263,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
|
||||||
args.Commitments = sidecar.Commitments
|
args.Commitments = sidecar.Commitments
|
||||||
args.Proofs = sidecar.Proofs
|
args.Proofs = sidecar.Proofs
|
||||||
}
|
}
|
||||||
|
return args, nil
|
||||||
var res signTransactionResult
|
|
||||||
if err := api.client.Call(&res, "account_signTransaction", args); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return res.Tx, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
||||||
|
|
|
||||||
81
accounts/external/backend_test.go
vendored
Normal file
81
accounts/external/backend_test.go
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2026 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 external
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSignTxArgsSetCodeAuthorizationList(t *testing.T) {
|
||||||
|
account := accounts.Account{Address: common.HexToAddress("0x1000000000000000000000000000000000000001")}
|
||||||
|
to := common.HexToAddress("0x2000000000000000000000000000000000000002")
|
||||||
|
auth := types.SetCodeAuthorization{
|
||||||
|
ChainID: *uint256.NewInt(5),
|
||||||
|
Address: common.HexToAddress("0x3000000000000000000000000000000000000003"),
|
||||||
|
Nonce: 9,
|
||||||
|
V: 1,
|
||||||
|
R: *uint256.NewInt(10),
|
||||||
|
S: *uint256.NewInt(11),
|
||||||
|
}
|
||||||
|
tx := types.NewTx(&types.SetCodeTx{
|
||||||
|
ChainID: uint256.NewInt(5),
|
||||||
|
Nonce: 4,
|
||||||
|
GasTipCap: uint256.NewInt(3),
|
||||||
|
GasFeeCap: uint256.NewInt(30),
|
||||||
|
Gas: 21000,
|
||||||
|
To: to,
|
||||||
|
Value: uint256.NewInt(7),
|
||||||
|
Data: []byte{0x01, 0x02},
|
||||||
|
AccessList: types.AccessList{{
|
||||||
|
Address: common.HexToAddress("0x4000000000000000000000000000000000000004"),
|
||||||
|
StorageKeys: []common.Hash{common.HexToHash("0x01")},
|
||||||
|
}},
|
||||||
|
AuthList: []types.SetCodeAuthorization{auth},
|
||||||
|
})
|
||||||
|
args, err := signTxArgs(account, tx, big.NewInt(1))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if args.ChainID == nil || (*big.Int)(args.ChainID).Cmp(big.NewInt(5)) != 0 {
|
||||||
|
t.Fatalf("have chain id %v, want 5", args.ChainID)
|
||||||
|
}
|
||||||
|
if args.MaxFeePerGas == nil || (*big.Int)(args.MaxFeePerGas).Cmp(big.NewInt(30)) != 0 {
|
||||||
|
t.Fatalf("have max fee %v, want 30", args.MaxFeePerGas)
|
||||||
|
}
|
||||||
|
if args.MaxPriorityFeePerGas == nil || (*big.Int)(args.MaxPriorityFeePerGas).Cmp(big.NewInt(3)) != 0 {
|
||||||
|
t.Fatalf("have max priority fee %v, want 3", args.MaxPriorityFeePerGas)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(args.AuthorizationList, []types.SetCodeAuthorization{auth}) {
|
||||||
|
t.Fatalf("have auth list %#v, want %#v", args.AuthorizationList, []types.SetCodeAuthorization{auth})
|
||||||
|
}
|
||||||
|
blob, err := json.Marshal(args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Contains(blob, []byte(`"authorizationList"`)) {
|
||||||
|
t.Fatalf("marshaled args missing authorizationList: %s", blob)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -112,6 +112,9 @@ type SendTxArgs struct {
|
||||||
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
|
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
|
||||||
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
|
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
|
||||||
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
|
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
|
||||||
|
|
||||||
|
// For SetCodeTxType
|
||||||
|
AuthorizationList []types.SetCodeAuthorization `json:"authorizationList,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (args SendTxArgs) String() string {
|
func (args SendTxArgs) String() string {
|
||||||
|
|
@ -146,6 +149,27 @@ func (args *SendTxArgs) ToTransaction() (*types.Transaction, error) {
|
||||||
}
|
}
|
||||||
var data types.TxData
|
var data types.TxData
|
||||||
switch {
|
switch {
|
||||||
|
case args.AuthorizationList != nil:
|
||||||
|
al := types.AccessList{}
|
||||||
|
if args.AccessList != nil {
|
||||||
|
al = *args.AccessList
|
||||||
|
}
|
||||||
|
if to == nil {
|
||||||
|
return nil, errors.New("transaction recipient must be set for set-code transactions")
|
||||||
|
}
|
||||||
|
data = &types.SetCodeTx{
|
||||||
|
To: *to,
|
||||||
|
ChainID: uint256.MustFromBig((*big.Int)(args.ChainID)),
|
||||||
|
Nonce: uint64(args.Nonce),
|
||||||
|
Gas: uint64(args.Gas),
|
||||||
|
GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
|
||||||
|
GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
|
||||||
|
Value: uint256.MustFromBig((*big.Int)(&args.Value)),
|
||||||
|
Data: args.data(),
|
||||||
|
AccessList: al,
|
||||||
|
AuthList: args.AuthorizationList,
|
||||||
|
}
|
||||||
|
|
||||||
case args.BlobHashes != nil:
|
case args.BlobHashes != nil:
|
||||||
al := types.AccessList{}
|
al := types.AccessList{}
|
||||||
if args.AccessList != nil {
|
if args.AccessList != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,16 @@
|
||||||
package apitypes
|
package apitypes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -99,6 +103,75 @@ func TestTxArgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetCodeTxArgs(t *testing.T) {
|
||||||
|
to := common.HexToAddress("0x1000000000000000000000000000000000000001")
|
||||||
|
from := common.NewMixedcaseAddress(common.HexToAddress("0x9000000000000000000000000000000000000009"))
|
||||||
|
mixedTo := common.NewMixedcaseAddress(to)
|
||||||
|
input := hexutil.Bytes{0x01, 0x02}
|
||||||
|
chainID := hexutil.Big(*big.NewInt(5))
|
||||||
|
maxFee := hexutil.Big(*big.NewInt(30))
|
||||||
|
maxTip := hexutil.Big(*big.NewInt(3))
|
||||||
|
value := hexutil.Big(*big.NewInt(7))
|
||||||
|
accessList := types.AccessList{{
|
||||||
|
Address: common.HexToAddress("0x2000000000000000000000000000000000000002"),
|
||||||
|
StorageKeys: []common.Hash{common.HexToHash("0x01")},
|
||||||
|
}}
|
||||||
|
auth := types.SetCodeAuthorization{
|
||||||
|
ChainID: *uint256.NewInt(5),
|
||||||
|
Address: common.HexToAddress("0x3000000000000000000000000000000000000003"),
|
||||||
|
Nonce: 9,
|
||||||
|
V: 1,
|
||||||
|
R: *uint256.NewInt(10),
|
||||||
|
S: *uint256.NewInt(11),
|
||||||
|
}
|
||||||
|
args := SendTxArgs{
|
||||||
|
From: from,
|
||||||
|
To: &mixedTo,
|
||||||
|
Gas: 21000,
|
||||||
|
MaxFeePerGas: &maxFee,
|
||||||
|
MaxPriorityFeePerGas: &maxTip,
|
||||||
|
Value: value,
|
||||||
|
Nonce: 4,
|
||||||
|
Input: &input,
|
||||||
|
AccessList: &accessList,
|
||||||
|
ChainID: &chainID,
|
||||||
|
AuthorizationList: []types.SetCodeAuthorization{auth},
|
||||||
|
}
|
||||||
|
blob, err := json.Marshal(args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Contains(blob, []byte(`"authorizationList"`)) {
|
||||||
|
t.Fatalf("marshaled args missing authorizationList: %s", blob)
|
||||||
|
}
|
||||||
|
var decoded SendTxArgs
|
||||||
|
if err := json.Unmarshal(blob, &decoded); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx, err := decoded.ToTransaction()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if have, want := tx.Type(), uint8(types.SetCodeTxType); have != want {
|
||||||
|
t.Fatalf("have tx type %d, want %d", have, want)
|
||||||
|
}
|
||||||
|
if have := tx.To(); have == nil || *have != to {
|
||||||
|
t.Fatalf("have to %v, want %v", have, to)
|
||||||
|
}
|
||||||
|
if have, want := tx.ChainId(), big.NewInt(5); have.Cmp(want) != 0 {
|
||||||
|
t.Fatalf("have chain id %v, want %v", have, want)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(tx.Data(), input) {
|
||||||
|
t.Fatalf("have input %x, want %x", tx.Data(), input)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(tx.AccessList(), accessList) {
|
||||||
|
t.Fatalf("have access list %#v, want %#v", tx.AccessList(), accessList)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(tx.SetCodeAuthorizations(), []types.SetCodeAuthorization{auth}) {
|
||||||
|
t.Fatalf("have auth list %#v, want %#v", tx.SetCodeAuthorizations(), []types.SetCodeAuthorization{auth})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBlobTxs(t *testing.T) {
|
func TestBlobTxs(t *testing.T) {
|
||||||
blob := kzg4844.Blob{0x1}
|
blob := kzg4844.Blob{0x1}
|
||||||
commitment, err := kzg4844.BlobToCommitment(&blob)
|
commitment, err := kzg4844.BlobToCommitment(&blob)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue