Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subxt fails to generate for BitVec type in public API, error message too long #1211

Closed
drahnr opened this issue Oct 19, 2023 · 16 comments
Closed

Comments

@drahnr
Copy link

drahnr commented Oct 19, 2023

appeared in the progress of upgrading from substrate 0.9.42 to 0.9.43 with subxt 0.29 as well as 0.30 and 0.31.

error[E0277]: the trait bound `DecodedBits<u8, order::Lsb0>: parity_scale_codec::Decode` is not satisfied
 --> /media/supersonic1t/projects/gensyn-ai/node-mathis-substrate-bump-v0.9.43/target/debug/build/gensyn-cli-1a91c111415b9596/out/codegen.rs:1:478390
  |
1 | ...subxt :: ext :: scale_encode")] pub struct AvailabilityThresholdBitfield (pub :: subxt :: utils :: bits :: DecodedBits < :: core :: primitive :: u8 , runtime_types :: bitvec :: order :: Lsb0 > ,) ; # [derive (:: subxt :: ext :: codec :: Decode ...
  |                                                                              ^^^ the trait `parity_scale_codec::Decode` is not implemented for `DecodedBits<u8, order::Lsb0>`
  |
  = help: the trait `parity_scale_codec::Decode` is implemented for `DecodedBits<Store, Order>`

error[E0277]: the trait bound `DecodedBits<u8, order::Lsb0>: parity_scale_codec::Encode` is not satisfied
 --> /media/supersonic1t/projects/gensyn-ai/node-mathis-substrate-bump-v0.9.43/target/debug/build/gensyn-cli-1a91c111415b9596/out/codegen.rs:1:478002
  |
1 | ... , :: subxt :: ext :: codec :: Encode , :: subxt :: ext :: scale_decode :: DecodeAsType , :: subxt :: ext :: scale_encode :: EncodeAsType , Clone , Debug , PartialEq)] # [codec (crate = :: subxt :: ext :: codec)] # [decode_as_type (crate_path = ":: subxt :: ext :: scale_decode")] # [encode_as_type (crate_path = ":: subxt :: ext :: scale_encode")] pub struct AvailabilityThresholdBitfield (pub ::...
  |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `parity_scale_codec::Encode` is not implemented for `DecodedBits<u8, order::Lsb0>`                                                        ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- required by a bound introduced by this call
  |
  = help: the trait `parity_scale_codec::Encode` is implemented for `DecodedBits<Store, Order>`
  = note: required for `&DecodedBits<u8, order::Lsb0>` to implement `parity_scale_codec::Encode`

error[E0277]: the trait bound `DecodedBits<u8, order::Lsb0>: parity_scale_codec::Decode` is not satisfied
 --> /media/supersonic1t/projects/gensyn-ai/node-mathis-substrate-bump-v0.9.43/target/debug/build/gensyn-cli-1a91c111415b9596/out/codegen.rs:1:479538
  |
1 | ...= ":: subxt :: ext :: scale_encode")] pub struct ShelfCommitmentBitfield (pub :: subxt :: utils :: bits :: DecodedBits < :: core :: primitive :: u8 , runtime_types :: bitvec :: order :: Lsb0 > ,) ; # [derive (:: subxt :: ext :: codec :: Decode ...
  |                                                                              ^^^ the trait `parity_scale_codec::Decode` is not implemented for `DecodedBits<u8, order::Lsb0>`
  |
  = help: the trait `parity_scale_codec::Decode` is implemented for `DecodedBits<Store, Order>`

error[E0277]: the trait bound `DecodedBits<u8, order::Lsb0>: parity_scale_codec::Encode` is not satisfied
 --> /media/supersonic1t/projects/gensyn-ai/node-mathis-substrate-bump-v0.9.43/target/debug/build/gensyn-cli-1a91c111415b9596/out/codegen.rs:1:479156
  |
1 | ... , :: subxt :: ext :: codec :: Encode , :: subxt :: ext :: scale_decode :: DecodeAsType , :: subxt :: ext :: scale_encode :: EncodeAsType , Clone , Debug , PartialEq)] # [codec (crate = :: subxt :: ext :: codec)] # [decode_as_type (crate_path = ":: subxt :: ext :: scale_decode")] # [encode_as_type (crate_path = ":: subxt :: ext :: scale_encode")] pub struct ShelfCommitmentBitfield (pub ::...
  |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `parity_scale_codec::Encode` is not implemented for `DecodedBits<u8, order::Lsb0>`                                                        ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- required by a bound introduced by this call
  |
  = help: the trait `parity_scale_codec::Encode` is implemented for `DecodedBits<Store, Order>`
  = note: required for `&DecodedBits<u8, order::Lsb0>` to implement `parity_scale_codec::Encode`

error[E0277]: the trait bound `DecodedBits<u8, order::Lsb0>: parity_scale_codec::Decode` is not satisfied
 --> /media/supersonic1t/projects/gensyn-ai/node-mathis-substrate-bump-v0.9.43/target/debug/build/gensyn-cli-1a91c111415b9596/out/codegen.rs:1:489851
  |
1 | ...< runtime_types :: gensyn_runtime_primitives :: indices :: ShelfIndex > , pub idx_is_validator : :: subxt :: utils :: bits :: DecodedBits < :: core :: primitive :: u8 , runtime_types :: bitvec :: order :: Lsb0 > , pub discovery_keys : :: std ::...
  |                                                                              ^^^ the trait `parity_scale_codec::Decode` is not implemented for `DecodedBits<u8, order::Lsb0>`
  |
  = help: the trait `parity_scale_codec::Decode` is implemented for `DecodedBits<Store, Order>`

error[E0277]: the trait bound `DecodedBits<u8, order::Lsb0>: parity_scale_codec::Encode` is not satisfied
 --> /media/supersonic1t/projects/gensyn-ai/node-mathis-substrate-bump-v0.9.43/target/debug/build/gensyn-cli-1a91c111415b9596/out/codegen.rs:1:489099
  |
1 | ... , :: subxt :: ext :: codec :: Encode , :: subxt :: ext :: scale_decode :: DecodeAsType , :: subxt :: ext :: scale_encode :: EncodeAsType , Clone , Debug , PartialEq)] # [codec (crate = :: subxt :: ext :: codec)] # [decode_as_type (crate_path = ":: subxt :: ext :: scale_decode")] # [encode_as_type (crate_path = ":: subxt :: ext :: scale_encode")] pub struct SessionInfo { pub random_seed : [:: core :: primitive :: u8 ; 32usize] , pub shelf_ids : runtime_types :: gensyn_runtime_primitives :: IndexedVec < runtime_types :: gensyn_runtime_primitives :: indices :: ShelfIndex , runtime_types :: sp_authority_discovery :: app :: Public > , pub active_indices : :: std :: vec :: Vec < runtime_types :: gensyn_runtime_primitives :: indices :: ShelfIndex > , pub id...
  |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `parity_scale_codec::Encode` is not implemented for `DecodedBits<u8, order::Lsb0>`                                                        -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- required by a bound introduced by this call
  |
  = help: the trait `parity_scale_codec::Encode` is implemented for `DecodedBits<Store, Order>`

...
@drahnr drahnr changed the title subxt generates inacceptably long error messages from generated code subxt fails to generate for BitVec type in public API, error message too long Oct 19, 2023
@lexnv
Copy link
Collaborator

lexnv commented Oct 19, 2023

Hey Bernhard,

Thanks for reaching out!

Looking at the error it seems that subxt is not able to derive Encode/Decode for:

struct AvailabilityThresholdBitfield(pub :: subxt :: utils :: bits :: DecodedBits < :: core :: primitive :: u8 , runtime_types :: bitvec :: order :: Lsb0 > ,)

However, since the DecodedBits are part of subxt, we provide implementations for those traits:

impl<Store: BitStore, Order: BitOrder> codec::Decode for DecodedBits<Store, Order> {

What I expect is happening is that we have different Codec crate dependencies which causes an incompatibility in ABIs

Most substrate dependencies are using:
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false }

While subxt is using
codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false }

I do agree indeed that the error is a bit too verbose, maybe there's something we can do about that

@jsdw
Copy link
Collaborator

jsdw commented Oct 19, 2023

@drahnr it might help if you could point us at a repo where you are seeing this issue; we could then check the above!

Offhand I'd assume that 3.4.0 and 3.6.1 were compatible and would lead to both using 3.6.1, but perhaps there is something in this area that is causing an issue!

@drahnr
Copy link
Author

drahnr commented Oct 19, 2023

parity-scale-codec = { version = "3", default-features = false } is our workspace level dependency and resolves to 3.6.x in our workspace.

@jsdw cannot provide source code at this time beyond

#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, std::hash::Hash))]
pub struct AvailabilityThresholdBitfield(pub BitVec<u8, bitvec::order::Lsb0>);

with

bitvec resolving to version 1.0.1

@drahnr
Copy link
Author

drahnr commented Oct 19, 2023

I do agree indeed that the error is a bit too verbose, maybe there's something we can do about that

The above is just the beginning, it exceeded my terminal buffer of 10000 lines scrollback.

@jsdw
Copy link
Collaborator

jsdw commented Oct 19, 2023

1 | ...subxt :: ext :: scale_encode")] pub struct AvailabilityThresholdBitfield (pub :: subxt :: utils :: bits :: DecodedBits < :: core :: primitive :: u8 , runtime_types :: bitvec :: order :: Lsb0 > ,) ; # [derive (:: subxt :: ext :: codec :: Decode ...
  |                                                                              ^^^ the trait `parity_scale_codec::Decode` is not implemented for `DecodedBits<u8, order::Lsb0>`

I think the issue here is this bit:

runtime_types :: bitvec :: order :: Lsb0

The type that should be in use there is:

::subxt::utils::bits::Lsb0

This is one of the type substitutions that we do by default because the generated type doesn't "make sense" and needs to be swapped with a type that does mean something (ie implements the Order trait or whatever). So i'm not sure why it isn't occurring for you, unless you've disabled it?

#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, std::hash::Hash))]
pub struct AvailabilityThresholdBitfield(pub BitVec<u8, bitvec::order::Lsb0>);

One vague guess I have is that you need to enable the bitvec feature in parity-scale-codec to make sure that we know how to encode/decode bitvecs, but that should already be enabled and I'd guess you'd hit an error far earlier if is wasn't enabled.

The version of BitVec there should be fine.

Hmmm... honestly I'd probably need some sort of reproducable example to be able to properly dig and work out why the type substitution isn't happening as expected (perhaps I could see how you've used the subxt macro?)

@jsdw
Copy link
Collaborator

jsdw commented Oct 19, 2023

I do agree indeed that the error is a bit too verbose, maybe there's something we can do about that

I'm not sure how much we can help with this; it's not a subxt specific error, but just a consequence of the Rust compiler complaining about lots of code that has been generated that isn't valid. We can hopefully work out what's happening with the codegen though, and may be able to either fix it or provide warnings when something that's likely to fail is encountered re options provided.

@drahnr
Copy link
Author

drahnr commented Oct 20, 2023

Enabling the "bit-vec" feature makes no difference.

@lexnv
Copy link
Collaborator

lexnv commented Oct 20, 2023

Interesting 🤔 Would you think it would be hard to provide a minimal reproducible example?

We could otherwise look at the generated code from substrate wrt the BitVec, however, that may end up not leading to this error and potentially be time-consuming

@jsdw
Copy link
Collaborator

jsdw commented Oct 20, 2023

Just to confirm, I built the latest polkadot binaries from master of polkadot-sdk, ran a node with:

polkadot --chain rococo-dev --force-authoring --alice

And then generated code from this node by running this in the subxt root:

cargo run --bin subxt -- codegen | rustfmt > TEMP.rs

I can see in that file that the substitutions have worked as expected, eg I see code like this:

pub votes_reject: ::subxt::utils::bits::DecodedBits<
    ::core::primitive::u8,
    ::subxt::utils::bits::Lsb0,
>,

And If I run this simple example with that polkadot node still running:

use subxt::{OnlineClient, PolkadotConfig};

// Don't point at a URL in production:
#[subxt::subxt(runtime_metadata_url="ws://localhost:9944")]
pub mod runtime {}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let _ = OnlineClient::<PolkadotConfig>::new().await?;
    Ok(())
}

Everything still works ok.

So I can't find any issue offhand, and without some reproduction of the error I don't think I can do anything more here.

@drahnr
Copy link
Author

drahnr commented Oct 20, 2023

Which version of substrate did you use? I am focused on substrate 0.9.43 in conjunction with subxt 0.29 or later, that info is missing from your post.

@jsdw
Copy link
Collaborator

jsdw commented Oct 20, 2023

I built the latest polkadot binaries from master of polkadot-sdk

My polkadot node was compiled from polkadot-sdk and is one commit off master now, precise version polkadot 1.1.0-69c986f4057.

The version of Subxt I used was 0.32.1 (although nothing significant has changed re type substitutions for a while).

During testing I also tried polkadot 0.9.43-d5616884690 and substrate-node 3.0.0-dev-69c986f4057 (an equally uptodate substrate node) and neither of these had a problem when running the above Subxt example code either.

Can you provide some example code, with specific versions, which runs into this issue?

@drahnr
Copy link
Author

drahnr commented Oct 20, 2023

I just tested your sample and it seems to work, in production we have a builder that pulls the runtime code, let me try this and if that's the root problem I can share the build.rs.

So far testing the example:

0.9.42 with 0.28 with our build.rs + runtime: ✔️
0.9.42 with 0.29 with the exact sample above: ✔️
0.9.42 with 0.29 with our build.rs + runtime: ❌
0.9.43 with 0.29 with the exact sample above: ✔️
0.9.43 with 0.29 with our build.rs + runtime: ❌

@jsdw @lexnv
https://github.com/drahnr/subxt-whopsi

@jsdw
Copy link
Collaborator

jsdw commented Oct 20, 2023

I think that your issue is here:

https://github.com/drahnr/subxt-whopsi/blob/0f39337f93731d3ab4765cc1c5cca768e454d614/build.rs#L62

Here, you don't enable all of the default type substitutes that would normally be enabled via the #[subxt] macro or subxt codegen command. Some of the substitutes are necessary in order that code generated with the default derives is valid.

You can probably fix this by using:

TypeSubstitutes::with_default_substitutes("::subxt".into())

(replacing "::subxt" with whatever the path that gets to the subxt crate is).

These codegen APIs are somewhat undocumented and are mainly internal details; we should probably give them a general tidy so that generating code via this sort of approach exposes the same sorts of options as generating the code via the mnacro or codegen CLI option, because right now it's easy to give options like this that lead to it being a bit naff!

@drahnr
Copy link
Author

drahnr commented Oct 22, 2023

TypeSubstitutes::with_default_substitutes(&CratePath::from("::subxt")) did the trick with (at least) subxt 0.30.1.

Thank you for taking the time looking into it!


I'd appreciate if you could document the codegen API a bit more, as well as providing Default impl of types such that the behavior is aligned to what the proc-macros would generate. At least that would have saved us quite a bit of debugging

@jsdw
Copy link
Collaborator

jsdw commented Oct 23, 2023

I'd appreciate if you could document the codegen API a bit more, as well as providing Default impl of types such that the behavior is aligned to what the proc-macros would generate. At least that would have saved us quite a bit of debugging

Yeah, I'll open an issue for this!

TBH, it's not really been part of the public interface I'd expected anybody to use because it's a bit messy in general, but I think we can probably hide most of it away and provide some sort of simple builder/entrypoint thing which allows for the same sort of configuration options as the macro/CLI tool :)

@jsdw
Copy link
Collaborator

jsdw commented Oct 23, 2023

I've opened #1221 to address this, so I'll close this issue now since your problem has been resolved! Thanks for raising!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants