4

I have a CLI tool that gets a WebAssembly runtime file:

let validation_code_content = fs::read_to_string(path_validation_code)
        .expect("Should have been able to read the validation code file");

If I print validation_code_content I can see the content is correct. Now I want to send this file into an extrinsic (e.g: register), which needs to be converted into the [ValidationCode][3] struct:

/// Parachain validation code.
#[derive(
    PartialEq,
    Eq,
    Clone,
    Encode,
    Decode,
    RuntimeDebug,
    derive_more::From,
    TypeInfo,
    Serialize,
    Deserialize,
)]
#[cfg_attr(feature = "std", derive(Hash))]
pub struct ValidationCode(#[serde(with = "bytes")] pub Vec<u8>);

I can see in the tests on the pallet that I need a vector of bytes:

fn test_validation_code(size: usize) -> ValidationCode {
        let validation_code = vec![0u8; size as usize];
        ValidationCode(validation_code)
}

So my approach is convert the String in the vector of bytes and cast it to ValidationCode:

    let validation_code = validation_code_content.into_bytes()
    let call = Call::Registrar(RegistrarCall::register {
        id: RococoId(para_id),
        genesis_head: HeadData(genesis_head),
        validation_code: ValidationCode(validation_code),
    });

The code compiles but the extrinsic fails because something is wrong with the validation code. Did I lose data when I am doing the conversion?

6
  • What error do you get?
    – bkchr
    Jun 24, 2023 at 19:36
  • I see the event PvfCheckRejected
    – Alex Bean
    Jun 26, 2023 at 8:17
  • Sounds like the validation code is maybe wrong? Probably because you read the validation code as string and then convert it to bytes. Use fs::read to directly read it as binary data.
    – bkchr
    Jun 27, 2023 at 12:34
  • I tried with fs::read first and I was getting the PvfCheckRejected too
    – Alex Bean
    Jun 27, 2023 at 18:45
  • Are you sure that the wasm file is correct?
    – bkchr
    Jul 1, 2023 at 20:00

2 Answers 2

0

I think there is something wrong with your call data.

I don't know which client you are using.

I guess you need to write something like this:

RegistrarCall::register {
    id: RococoId(para_id),
    genesis_head: HeadData(genesis_head),
    validation_code: ValidationCode(validation_code),
}.encode()

Or

RegistrarCall::register {
    id: RococoId(para_id).encode(),
    genesis_head: HeadData(genesis_head).encode(),
    validation_code: ValidationCode(validation_code).encode(),
}
2
  • Sorry I skip some parts of the code to only focus on this call construction,I am using subxt and after it I construct the transaction propertly.
    – Alex Bean
    Jun 23, 2023 at 9:30
  • You shouldn't need to call .encode() on any of the "inner" things I think; just the outermost call (ie the top option here). But I'd need to be able to reproduce the issue with a complete code sample to be much help here I think.
    – jsdw
    Jun 30, 2023 at 11:55
0

Finally I found the solution, as suspected was related to the conversion of the WASM file. Checking how the WASM runtime file is generated here:

Some(cli::Subcommand::ExportGenesisWasm(_params)) => {
            let collator = Collator::new();
            println!("0x{:?}", HexDisplay::from(&collator.validation_code()));

            Ok(())
}

The first thing that has to be done is remove the 0x in the file, an easy way to do it is deleting the first 2 characters:

validation_code.remove(0);
validation_code.remove(0);  

And as seen in the code, the format of the file is hex, so importing the hex library in the Cargo and decoding the hex will make the proper conversion to bytes.

let code = hex::decode(validation_code).expect("Decoding failed"):

And now with the cast ValidationCode(code) it works in the extrinsic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.