mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
ethclient: require inclusion block for TransactionSender
This commit is contained in:
parent
81651c38da
commit
302bc9f7fb
2 changed files with 26 additions and 19 deletions
|
|
@ -20,6 +20,7 @@ package ethclient
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
|
@ -166,6 +167,7 @@ type rpcTransaction struct {
|
||||||
|
|
||||||
type txExtraInfo struct {
|
type txExtraInfo struct {
|
||||||
BlockNumber *string
|
BlockNumber *string
|
||||||
|
BlockHash common.Hash
|
||||||
From common.Address
|
From common.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,29 +189,33 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *
|
||||||
} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
|
} else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
|
||||||
return nil, false, fmt.Errorf("server returned transaction without signature")
|
return nil, false, fmt.Errorf("server returned transaction without signature")
|
||||||
}
|
}
|
||||||
setSenderFromServer(json.tx, json.From)
|
setSenderFromServer(json.tx, json.From, json.BlockHash)
|
||||||
return json.tx, json.BlockNumber == nil, nil
|
return json.tx, json.BlockNumber == nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionSender returns the sender address of the given transaction. The transaction
|
// TransactionSender returns the sender address of the given transaction. The transaction
|
||||||
// must be known to the remote node. The sender is the one derived by the protocol at the
|
// must be known to the remote node and included in the blockchain. The sender is the one
|
||||||
// time of inclusion.
|
// derived by the protocol at the time of inclusion.
|
||||||
//
|
//
|
||||||
// There is a fast-path for transactions retrieved by TransactionByHash and
|
// There is a fast-path for transactions retrieved by TransactionByHash and
|
||||||
// TransactionInBlock. Getting their sender address can be done without an RPC interaction.
|
// TransactionInBlock. Getting their sender address can be done without an RPC interaction.
|
||||||
func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction) (common.Address, error) {
|
func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
|
||||||
// Try to load the address from the cache.
|
// Try to load the address from the cache.
|
||||||
sender, err := types.Sender((*senderFromServer)(nil), tx)
|
sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return sender, nil
|
return sender, nil
|
||||||
}
|
}
|
||||||
// TODO It'd better to use GetTransactionByBlockHashAndIndex because it works with the
|
var meta struct {
|
||||||
// light client. This will be even more important with EIP 208 because there can be
|
Hash common.Hash
|
||||||
// multiple inclusions of the same tx. The downside is that users would need to supply
|
From common.Address
|
||||||
// the inclusion block.
|
}
|
||||||
var meta struct{ From common.Address }
|
if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
|
||||||
err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByHash", tx.Hash())
|
return common.Address{}, err
|
||||||
return meta.From, err
|
}
|
||||||
|
if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
|
||||||
|
return common.Address{}, errors.New("wrong inclusion block/index")
|
||||||
|
}
|
||||||
|
return meta.From, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionCount returns the total number of transactions in the given block.
|
// TransactionCount returns the total number of transactions in the given block.
|
||||||
|
|
@ -230,7 +236,7 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
|
||||||
return nil, fmt.Errorf("server returned transaction without signature")
|
return nil, fmt.Errorf("server returned transaction without signature")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSenderFromServer(json.tx, json.From)
|
setSenderFromServer(json.tx, json.From, json.BlockHash)
|
||||||
return json.tx, err
|
return json.tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,23 +28,24 @@ import (
|
||||||
// server. It is stored in the transaction's sender address cache to avoid an additional
|
// server. It is stored in the transaction's sender address cache to avoid an additional
|
||||||
// request in TransactionSender.
|
// request in TransactionSender.
|
||||||
type senderFromServer struct {
|
type senderFromServer struct {
|
||||||
addr common.Address
|
addr common.Address
|
||||||
|
blockhash common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
var errNotCached = errors.New("sender not cached")
|
var errNotCached = errors.New("sender not cached")
|
||||||
|
|
||||||
func setSenderFromServer(tx *types.Transaction, addr common.Address) {
|
func setSenderFromServer(tx *types.Transaction, addr common.Address, block common.Hash) {
|
||||||
// Use types.Sender for side-effect to store our signer into the cache.
|
// Use types.Sender for side-effect to store our signer into the cache.
|
||||||
types.Sender(&senderFromServer{addr}, tx)
|
types.Sender(&senderFromServer{addr, block}, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *senderFromServer) Equal(other types.Signer) bool {
|
func (s *senderFromServer) Equal(other types.Signer) bool {
|
||||||
_, ok := other.(*senderFromServer)
|
os, ok := other.(*senderFromServer)
|
||||||
return ok
|
return ok && os.blockhash == s.blockhash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error) {
|
func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error) {
|
||||||
if s == nil {
|
if s.blockhash == (common.Hash{}) {
|
||||||
return common.Address{}, errNotCached
|
return common.Address{}, errNotCached
|
||||||
}
|
}
|
||||||
return s.addr, nil
|
return s.addr, nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue