You will have to declare that you require Trait<N> to be implemented. N can be pretty much anything, after all. If you add where StructBottom<N>: Trait<N> to the function or impl block that requires it, foo should become usable.
StructBottom<N> only implements Trait<N> when N = u8. (And Rust only allows you to make use traits which are actually implemented, backed up by the trait bounds. Unlike some template systems.)
So use one of these approaches.
-impl<N> StructTop<N> {
+impl<N> StructTop<N> where StructBottom<N>: Trait<N> {
Trait bounds don't constrain the left-hand side; they constrain any free type variables that appear in the where clause, whether they stand alone, embedded in a more complex type expression, and regardless of whether they are on the LHS or RHS of a bound.
This is similar to algebra, where the equation x + 2 = 3 doesn't constrain the numbers 2 or 3. It constrains the variable x. The equation doesn't mean "re-define all of math so that x + 2 = 3 for all x". It instead means "x must be 1", even if you exchange the two sides of the equality, and even if you write it in a more roundabout way such as 1 + x + 1 = 5 - 2.
It's easy to assume that the where clause can't access anything other than the type parameters (and maybe Self), especially if you learn it as an alternative to the <T: Blah> syntax. It took a while for that puzzle piece to fully fall into place for me as well.
It's basically a list of general constraints or assumptions that need to hold for the implementation to work. It's powerful, but of course also opens up for some amount of viral spaghetti.
I think my favorite learning about how they work, and something people sometimes misunderstand, is that you don't always need to list all of the transitive requirements. Let's say your StructBottom also had a generic implementation with its own requirements. You don't need to repeat them for StructTop, unless you specifically need them there too.