Commit d1920d8f authored by Ralph Pichler's avatar Ralph Pichler Committed by GitHub

use eip155 signing in in-memory signer (#1338)

parent 4e05c8ad
......@@ -109,7 +109,7 @@ func (c *clefSigner) Sign(data []byte) ([]byte, error) {
}
// SignTx signs an ethereum transaction.
func (c *clefSigner) SignTx(transaction *types.Transaction) (*types.Transaction, error) {
func (c *clefSigner) SignTx(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
// chainId is nil here because it is set on the clef side
return c.clef.SignTx(c.account, transaction, nil)
}
......
......@@ -6,6 +6,7 @@ package mock
import (
"crypto/ecdsa"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
......@@ -14,7 +15,7 @@ import (
)
type signerMock struct {
signTx func(transaction *types.Transaction) (*types.Transaction, error)
signTx func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error)
signTypedData func(*eip712.TypedData) ([]byte, error)
ethereumAddress func() (common.Address, error)
}
......@@ -30,8 +31,8 @@ func (*signerMock) Sign(data []byte) ([]byte, error) {
return nil, nil
}
func (m *signerMock) SignTx(transaction *types.Transaction) (*types.Transaction, error) {
return m.signTx(transaction)
func (m *signerMock) SignTx(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
return m.signTx(transaction, chainID)
}
func (*signerMock) PublicKey() (*ecdsa.PublicKey, error) {
......@@ -59,7 +60,7 @@ type optionFunc func(*signerMock)
func (f optionFunc) apply(r *signerMock) { f(r) }
func WithSignTxFunc(f func(transaction *types.Transaction) (*types.Transaction, error)) Option {
func WithSignTxFunc(f func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error)) Option {
return optionFunc(func(s *signerMock) {
s.signTx = f
})
......
......@@ -8,6 +8,7 @@ import (
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/common"
......@@ -23,7 +24,7 @@ type Signer interface {
// Sign signs data with ethereum prefix (eip191 type 0x45).
Sign(data []byte) ([]byte, error)
// SignTx signs an ethereum transaction.
SignTx(transaction *types.Transaction) (*types.Transaction, error)
SignTx(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error)
// SignTypedData signs data according to eip712.
SignTypedData(typedData *eip712.TypedData) ([]byte, error)
// PublicKey returns the public key this signer uses.
......@@ -88,8 +89,9 @@ func (d *defaultSigner) Sign(data []byte) (signature []byte, err error) {
}
// SignTx signs an ethereum transaction.
func (d *defaultSigner) SignTx(transaction *types.Transaction) (*types.Transaction, error) {
hash := (&types.HomesteadSigner{}).Hash(transaction).Bytes()
func (d *defaultSigner) SignTx(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
txSigner := types.NewEIP155Signer(chainID)
hash := txSigner.Hash(transaction).Bytes()
// isCompressedKey is false here so we get the expected v value (27 or 28)
signature, err := d.sign(hash, false)
if err != nil {
......@@ -98,7 +100,7 @@ func (d *defaultSigner) SignTx(transaction *types.Transaction) (*types.Transacti
// v value needs to be adjusted by 27 as transaction.WithSignature expects it to be 0 or 1
signature[64] -= 27
return transaction.WithSignature(&types.HomesteadSigner{}, signature)
return transaction.WithSignature(txSigner, signature)
}
// EthereumAddress returns the ethereum address this signer uses.
......
......@@ -101,14 +101,16 @@ func TestDefaultSignerSignTx(t *testing.T) {
signer := crypto.NewDefaultSigner(privKey)
beneficiary := common.HexToAddress("8d3766440f0d7b949a5e32995d09619a7f86e632")
tx, err := signer.SignTx(types.NewTransaction(0, beneficiary, big.NewInt(0), 21000, big.NewInt(1), []byte{1}))
chainID := big.NewInt(10)
tx, err := signer.SignTx(types.NewTransaction(0, beneficiary, big.NewInt(0), 21000, big.NewInt(1), []byte{1}), chainID)
if err != nil {
t.Fatal(err)
}
expectedR := math.MustParseBig256("0x28815033e9b5b7ec32e40e3c90b6cd499c12de8a7da261fdad8b800c845b88ef")
expectedS := math.MustParseBig256("0x71f1c08f754ee36e0c9743a2240d4b6640ea4d78c8dc2d83a599bdcf80ef9d5f")
expectedV := math.MustParseBig256("0x1c")
expectedR := math.MustParseBig256("0x2937d18005a8236330b95c6b271ff46b06d5bf25355a06ff50939c9023245a99")
expectedS := math.MustParseBig256("0xcd7c13b2bb88a3d99004a80898fc05b50263f445f6c53ef7baf7ffca0e4a1bf")
expectedV := math.MustParseBig256("0x37")
v, r, s := tx.RawSignatureValues()
......
......@@ -153,19 +153,20 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
if err != nil {
return nil, err
}
transactionService, err := transaction.NewService(logger, swapBackend, signer, stateStore)
chainID, err := swapBackend.ChainID(p2pCtx)
if err != nil {
return nil, err
logger.Infof("could not connect to backend at %v. In a swap-enabled network a working blockchain node (for goerli network in production) is required. Check your node or specify another node using --swap-endpoint.", o.SwapEndpoint)
return nil, fmt.Errorf("could not get chain id from ethereum backend: %w", err)
}
overlayEthAddress, err = signer.EthereumAddress()
transactionService, err := transaction.NewService(logger, swapBackend, signer, stateStore, chainID)
if err != nil {
return nil, err
}
chainID, err := swapBackend.ChainID(p2pCtx)
overlayEthAddress, err = signer.EthereumAddress()
if err != nil {
logger.Infof("could not connect to backend at %v. In a swap-enabled network a working blockchain node (for goerli network in production) is required. Check your node or specify another node using --swap-endpoint.", o.SwapEndpoint)
return nil, fmt.Errorf("could not get chain id from ethereum backend: %w", err)
return nil, err
}
var factoryAddress common.Address
......
......@@ -56,20 +56,23 @@ type transactionService struct {
signer crypto.Signer
sender common.Address
store storage.StateStorer
chainID *big.Int
}
// NewService creates a new transaction service.
func NewService(logger logging.Logger, backend Backend, signer crypto.Signer, store storage.StateStorer) (Service, error) {
func NewService(logger logging.Logger, backend Backend, signer crypto.Signer, store storage.StateStorer, chainID *big.Int) (Service, error) {
senderAddress, err := signer.EthereumAddress()
if err != nil {
return nil, err
}
return &transactionService{
logger: logger,
backend: backend,
signer: signer,
sender: senderAddress,
store: store,
chainID: chainID,
}, nil
}
......@@ -88,7 +91,7 @@ func (t *transactionService) Send(ctx context.Context, request *TxRequest) (txHa
return common.Hash{}, err
}
signedTx, err := t.signer.SignTx(tx)
signedTx, err := t.signer.SignTx(tx, t.chainID)
if err != nil {
return common.Hash{}, err
}
......
......@@ -27,9 +27,9 @@ func nonceKey(sender common.Address) string {
return fmt.Sprintf("transaction_nonce_%x", sender)
}
func signerMockForTransaction(signedTx *types.Transaction, sender common.Address, t *testing.T) crypto.Signer {
func signerMockForTransaction(signedTx *types.Transaction, sender common.Address, signerChainID *big.Int, t *testing.T) crypto.Signer {
return signermock.New(
signermock.WithSignTxFunc(func(transaction *types.Transaction) (*types.Transaction, error) {
signermock.WithSignTxFunc(func(transaction *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
if signedTx.To() == nil {
if transaction.To() != nil {
t.Fatalf("signing transaction with recipient. wanted nil, got %x", transaction.To())
......@@ -45,6 +45,9 @@ func signerMockForTransaction(signedTx *types.Transaction, sender common.Address
if transaction.Value().Cmp(signedTx.Value()) != 0 {
t.Fatalf("signing transaction with wrong value. wanted %d, got %d", signedTx.Value(), transaction.Value())
}
if chainID.Cmp(signerChainID) != 0 {
t.Fatalf("signing transaction with wrong chainID. wanted %d, got %d", signerChainID, transaction.ChainId())
}
if transaction.Gas() != signedTx.Gas() {
t.Fatalf("signing transaction with wrong gas. wanted %d, got %d", signedTx.Gas(), transaction.Gas())
}
......@@ -73,6 +76,7 @@ func TestTransactionSend(t *testing.T) {
suggestedGasPrice := big.NewInt(2)
estimatedGasLimit := uint64(3)
nonce := uint64(2)
chainID := big.NewInt(5)
t.Run("send", func(t *testing.T) {
signedTx := types.NewTransaction(nonce, recipient, value, estimatedGasLimit, suggestedGasPrice, txData)
......@@ -111,8 +115,9 @@ func TestTransactionSend(t *testing.T) {
return nonce - 1, nil
}),
),
signerMockForTransaction(signedTx, sender, t),
signerMockForTransaction(signedTx, sender, chainID, t),
store,
chainID,
)
if err != nil {
t.Fatal(err)
......@@ -170,8 +175,9 @@ func TestTransactionSend(t *testing.T) {
return nonce, nil
}),
),
signerMockForTransaction(signedTx, sender, t),
signerMockForTransaction(signedTx, sender, chainID, t),
store,
chainID,
)
if err != nil {
t.Fatal(err)
......@@ -234,8 +240,9 @@ func TestTransactionSend(t *testing.T) {
return nextNonce, nil
}),
),
signerMockForTransaction(signedTx, sender, t),
signerMockForTransaction(signedTx, sender, chainID, t),
store,
chainID,
)
if err != nil {
t.Fatal(err)
......@@ -292,8 +299,9 @@ func TestTransactionSend(t *testing.T) {
return nonce, nil
}),
),
signerMockForTransaction(signedTx, sender, t),
signerMockForTransaction(signedTx, sender, chainID, t),
storemock.NewStateStore(),
chainID,
)
if err != nil {
t.Fatal(err)
......@@ -313,6 +321,7 @@ func TestTransactionSend(t *testing.T) {
func TestTransactionWaitForReceipt(t *testing.T) {
logger := logging.New(ioutil.Discard, 0)
txHash := common.HexToHash("0xabcdee")
chainID := big.NewInt(5)
transactionService, err := transaction.NewService(logger,
backendmock.New(
......@@ -324,6 +333,7 @@ func TestTransactionWaitForReceipt(t *testing.T) {
),
signermock.New(),
nil,
chainID,
)
if err != nil {
t.Fatal(err)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment