code: 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.
  	sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
  	if err == nil {
  		return sender, nil
  	}
  	var meta struct {
  		Hash common.Hash
  		From common.Address
  	}
  	if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
  		return common.Address{}, err
  	}
  	if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
  		return common.Address{}, errors.New("wrong inclusion block/index")
  	}
  	return meta.From, nil
  }
docs: // TransactionSender returns the sender address of the given transaction. The transaction
  // must be known to the remote node and included in the blockchain at the given block and
  // index. The sender is the one derived by the protocol at the time of inclusion.
  //
  // There is a fast-path for transactions retrieved by TransactionByHash and
  // TransactionInBlock. Getting their sender address can be done without an RPC interaction.