Why Initializing the structure with a newtype doesn't work?

hi, I am working on the parity Ethereum code. However, I faced some weird error when I tried to initialize a structure with newtype. please help me.

here is the troublesome code

    let transaction = Transaction::AssetTransfer {
        network_id: NetworkId([0u8; 2]),
        burns: Vec::new(),
        inputs: Vec::new(),
        outputs: Vec::new(),
        nonce: 0,
    };

and here is compile error

error[E0423]: expected function, found struct `NetworkId`
  --> vm/src/tests/executor.rs:76:21
   |
76 |         network_id: NetworkId([0u8; 2]),
   |                     ^^^^^^^^^ did you mean `NetworkId { /* fields */ }`?

and NetworkId is defined as follow

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct NetworkId([u8; 2]);

impl fmt::Display for NetworkId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let s = str::from_utf8(&self.0).expect("network_id a valid utf8 string");
        write!(f, "{}", s)
    }
}

impl FromStr for NetworkId {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() != 2 {
            return Err("Invalid network_id length".to_string())
        }
        let mut network_id = [0u8; 2];
        network_id.copy_from_slice(s.as_bytes());
        Ok(NetworkId(network_id))
    }
}

impl From<&'static str> for NetworkId {
    fn from(s: &'static str) -> Self {
        s.parse().unwrap()
    }
}

impl Default for NetworkId {
    fn default() -> Self {
        "tc".into()
    }
}

and Transaction::AssetTransfer is defined as follow

pub enum Transaction {
  ...
    AssetTransfer {
        network_id: NetworkId,
        burns: Vec<AssetTransferInput>,
        inputs: Vec<AssetTransferInput>,
        outputs: Vec<AssetTransferOutput>,
        nonce: u64,
    },
}

I think it should work..

Perhaps your newtype struct is not imported in current scope, and there is a normal struct of the same name NetworkId already defined/imported in the scope.

Tips:

  1. Sometimes the compiler will give you suggestions starting with “help: “, it may resolve your problem.

  2. You can use this to show minimal code for reproduction

use ckey::{sign, KeyPair, Private, Signature, NetworkId};

I already imported NetworkId from module where it is defined and there is no another struct named NetworkId.

and Thank to your tips

Is it because the NetworkId field isn't pub?

NetworkId field is pub and is declared in key/src/lib.rs as follow

pub use network::NetworkId;

and NetworkId is defined in key/src/network.rs

Not in the code you pasted:

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct NetworkId([u8; 2]);

NetworkId.0 is not pub. It shouldn't be visible to anyone outside the defining module, which would presumably include the code trying to create it.

Edit: also, "field" means a storage member of a structure. pub use is not a field, it's a public use item. NetworkId is a structure type.

1 Like

Additionally i do not know if that helps, troublesome code is test code.


#[test]
fn simple_success() {
    let transaction = Transaction::AssetTransfer {
        network_id: NetworkId([0u8; 2]),
        burns: Vec::new(),
        inputs: Vec::new(),
        outputs: Vec::new(),
        nonce: 0,
    };
    let outpoint = AssetOutPoint {
        transaction_hash: H256::default(),
        index: 0,
        asset_type: H256::default(),
        amount: 0,
    };
    assert_eq!(
        execute(&[], &[], &[Instruction::Push(1)], &transaction, Config::default(), &outpoint),
        Ok(ScriptResult::Unlocked)
    );

    assert_eq!(
        execute(&[], &[], &[Instruction::Success], &transaction, Config::default(), &outpoint),
        Ok(ScriptResult::Unlocked)
    );
}

Yes you are right!

After change NetworkId.0 to pub, I could make NetworkId in another module.

and thank to your explanation about filed