i've created my first substrate project successful and the built pallet also works fine. Now i wanted to create tests for the flow and the provided functions.
My flow is to generate a random hash and store this hash associated to the sender of the transaction
let _sender = ensure_signed(origin)?;
let nonce = Nonce::get();
let _random_seed = <randomness_collective_flip::Module<T>>::random_seed();
let random_hash = (_random_seed, &_sender, nonce).using_encoded(T::Hashing::hash);
ensure!(!<Hashes<T>>::contains_key(random_hash), "This new id already exists");
let _now = <timestamp::Module<T>>::get();
let new_elem = HashElement {
id: random_hash,
parent: parent,
updated: _now,
created: _now
};
<Hashes<T>>::insert(random_hash, new_pid);
<HashOwner<T>>::insert(random_hash, &_sender);
Self::deposit_event(RawEvent::Created(random_hash, _sender));
Ok(())
works good so far, when now i want to test the flow with a written test, i want to check if the hash emitted in the Created event is also assigned in the HashOwner Map. For this i need to get the value out of the event back.
And this is my problem :D i'm not professional in rust and all examples i found are expecting all values emitted in the event like this:
// construct event that should be emitted in the method call directly above
let expected_event = TestEvent::generic_event(RawEvent::EmitInput(1, 32));
// iterate through array of `EventRecord`s
assert!(System::events().iter().any(|a| a.event == expected_event));
When debugging my written test:
assert_ok!(TemplateModule::create_hash(Origin::signed(1), None));
let events = System::events();
let lastEvent = events.last().unwrap();
let newHash = &lastEvent.event;
i see in VSCode that the values are available:
debug window of vs code
but i dont know how to get this Hash in a variable back... maybe this is only a one liner ... but my rust knowledge is damn too small :D
thank you for your help
Here's a somewhat generic example of how to parse and check events, if you only care about the last event that your module put in system and nothing else.
assert_eq!(
System::events()
// this gives you an EventRecord { event: ..., ...}
.into_iter()
// map into the inner `event`.
.map(|r| r.event)
// the inner event is like `OuterEvent::mdouleEvent(EventEnum)`. The name of the outer
// event comes from whatever you have placed in your `delc_event! {}` in test mocks.
.filter_map(|e| {
if let MetaEvent::templateModule(inner) = e {
Some(inner)
} else {
None
}
})
.last()
.unwrap(),
// RawEvent is defined and imported in the template.rs file.
// val1 and val2 are things that you want to assert against.
RawEvent::Created(val1, val2),
);
Indeed you can also omit the first map or do it in more compact ways, but I have done it like this so you can see it step by step.
Print the System::events(), this also helps.
I now got it from the response of kianenigma :)
I wanted to reuse the given data in the event:
let lastEvent = System::events()
// this gives you an EventRecord { event: ..., ...}
.into_iter()
// map into the inner `event`.
.map(|r| r.event)
// the inner event is like `OuterEvent::mdouleEvent(EventEnum)`. The name of the outer
// event comes from whatever you have placed in your `delc_event! {}` in test mocks.
.filter_map(|e| {
if let TestEvent::pid(inner) = e {
Some(inner)
} else {
None
}
})
.last()
.unwrap();
if let RawEvent::Created(newHash, initiatedAccount) = lastEvent {
// there are the values :D
}
this can maybe be written better but this helps me :)
Related
I am familiar with Gstreamer but new to Rust,
TLDR; I want to be able to initialize PadProbeId to a default value before using it.
The details:
I have a Bin (containing audio + video encoders and hlssink).
I have been able to add this bin to the pipeline and it works fine.
The issue I have is the audio for the stream is optional and I want to do add_probe() only when audio is available. Below is a simplified version fo what I tried to implement
let mut audio_probe_id: PadProbeId;
let mut tee_audio_pad: Pad;
if media_info.audio_available {
// get encoded audio from the tee
tee_audio_pad = audio_tee.request_pad_simple("src_%u").unwrap();
audio_probe_id = tee_audio_pad.add_probe(gst::PadProbeType::BLOCK_DOWNSTREAM, |_pad, _info| {
gst::PadProbeReturn::Ok
}).unwrap();
// link the audio_tee.src to enc_bin ghost pad
let audio_sink_pad = enc_bin.static_pad("audio").unwrap();
tee_audio_pad.link(&audio_sink_pad).unwrap();
}
enc_bin.call_async(move |bin| {
bin.sync_state_with_parent().unwrap();
if media_info.audio_available {
tee_audio_pad.remove_probe(audio_probe_id);
}
}
However because of Rust compilers restriction to using uninitialized variables, it does not let me use audio_probe_id without initializing.
I tried to initialize it like this; let mut audio_probe_id: PadProbeId = PadProbeId(NonZeroU64(u64::MAX));. However compiler complains that it is a private field.
error[E0423]: cannot initialize a tuple struct which contains private fields
Thanks a lot for your help!
The rust way to have empty variables like this is to use Option, but in your case it would simpler to have a single conditional:
if media_info.audio_available {
// get encoded audio from the tee
let tee_audio_pad = audio_tee.request_pad_simple("src_%u").unwrap();
let audio_probe_id = tee_audio_pad.add_probe(gst::PadProbeType::BLOCK_DOWNSTREAM, |_pad, _info| {
gst::PadProbeReturn::Ok
}).unwrap();
// link the audio_tee.src to enc_bin ghost pad
let audio_sink_pad = enc_bin.static_pad("audio").unwrap();
tee_audio_pad.link(&audio_sink_pad).unwrap();
enc_bin.call_async(move |bin| {
bin.sync_state_with_parent().unwrap();
tee_audio_pad.remove_probe(audio_probe_id);
}
} else {
enc_bin.call_async(move |bin| {
bin.sync_state_with_parent().unwrap();
});
}
Hi all I am trying to access the values passed in the event .
I have extract the event with this - not this is substrate 0.9.12 so I have not been able to use some of the examples I find online that use substrate 2.0.0
let e = &frame_system::Pallet::<Test>::events()[0];
let EventRecord { event, .. } = e;
And this is the structure of event
Event::MosaicVault(
Event::VaultCreated {
sender: 1,
asset_id: A,
vault_id: 1,
reserved: Perquintill(
1000000000000000000,
),
},
)
How do I access vault_id value , a sample would be helpful , thanks
This is called destructuring of enum (if you want to search online for more example).
Basically you can use some match or if let to get the inner fields of some variants of enums.
something a bit like this:
if let Event::MosaicVault(Event::VaultCreated { vault_id, .. }) = event {
// here you have access to vault_id
}
I'm trying to capture errors on Rust, but I don't want the program to exit if I found it. I'm very new to Rust. Basically, I want to find a key from the Windows registry and if it doesn't exist, then create it.
Im using a crate called winreg for that.
This would be a section of my program:
fn main() -> io::Result<()> {
...
...
...
key.set_value("TestSZ", &"written by Rust")?;
// here I'm getting a value that exists
let sz_val: String = key.get_value("TestSZ")?;
// but this key doesn't exist
let other: String = key.get_value("NOT_EXISTING_KEY")?;
println!("TestSZ = {}", sz_val);
println!("TestSZ = {}", other);
Ok(())
}
If I compile that I receive this in the console:
And now lets write something...
An existing key has been opened
TestSZ = written by Rust
Error: Os { code: 2, kind: NotFound, message: "Couldn't find the pecified file." }
error: process didn't exit successfully: `target\debug\playground.exe` (exit code: 1)
In a pseudocode way, I would like something like:
if other == null {
println!("Nothing found!");
create_key();
}
If I analize get_value it looks like this:
pub fn get_value<T: FromRegValue, N: AsRef<OsStr>>(&self, name: N) -> io::Result<T>
I don't know what that means. I've been reading about errors and everything I do fails.
If I do let other: String = key.get_value("NOT_EXISTING_KEY").expect("Failed to read product name"); then the program exits, showing the error.
But I don't want the program to fail, I want to capture the error and do a different flow if I don't find the key (for example, create it).
Does anyone know how can I deal with this?
In Rust, a function that can fail usually returns a Result<OkType, ErrorType> data type. This type is a structured enum, which means, that it can tell you not only if error has occured, but also what kind of error, so you could act accordingly.
You can process enums with match statements. Or alternatively, Result type has shortcuts like Result::unwrap or Result::expect that basically say: "If there is an error, just tell me what kind and crash the program."
I'm not very familiar with Windows Registry, so I'm not sure how bulletproof the following code snippet is, but it should give you an idea on how you can process errors with a match statement.
fn main() {
// ...
let anykey_value = match key.get_value("AnyKey") {
// If the key is present, initialize `anykey_value` variable
// with the returned value
Ok(value) => value,
// If the key is not found, do the following steps:
Err(error) => {
println!("Nothing found!");
// Try to set an empty string as the value for "AnyKey".
// If fails: panic with the following message.
key.set_value("AnyKey", &"").expect("Failed to create key \"AnyKey\"");
// Initialize `anykey_value` variable with an empty string.
""
}
}
// Will print the value stored in "AnyKey"
// or an empty string, if the key was just created.
println!("AnyKey = {}", anykey_value);
// ...
}
Also you can checkout Error handling chapter from The Rust Programming Language book. It might be helpful.
I got it this way:
match key.get_value("NOT_EXISTING_KEY") {
Ok(value) => {
println!("found: {}", value);
value
},
Err(err) => {
println!("not found: {}", err);
String::from("")},
};
It was expecting a String
I need to process a slice of bytes into fixed chunks, but the chunk pattern is only known at runtime:
pub fn process(mut message: &[u8], pattern: &[Pattern]) {
for element in pattern: {
match element {
(...) => {
let (chunk, message2) = message.split_at(element.size);
/* process chunk */
message = message2;
},
// ...
}
}
}
It feels awkward to have to use this message2. But if I do
let (chunk, message) = message.split_at(element.size);
Then it does not work, I assume because this actually creates a new messages binding that goes out of scope between loop iterations.
Is there a more elegant way to do this?
You are correct in your reasoning that let (chunk, message) = message.split_at(element.size); creates a new binding message within that scope and does not update the outer message value.
What you are looking for is a 'destructuring assignment' of the tuple. This would allow tuple elements to be assigned to existing variable bindings instead of creating new bindings, something like:
let chunk;
(chunk, message) = message.split_at(element.size);
Unfortunately this is currently not possible in Rust. You can see a pre-RFC which proposes to add destructuring assignment to the Rust language.
I believe what you currently have is a perfectly fine solution, perhaps rename message2 to something like rest_of_message or remaining_message.
What is the best way to check a hash map for a key?
Currently I am using this:
let hashmap = HashMap::<&str, &str>::new(); // Empty hashmap
let name = "random";
for i in 0..5000000 {
if !hashmap.contains_key(&name) {
// Do nothing
}
}
This seems to be fast in most cases and takes 0.06 seconds when run as shown, but when I use it in this following loop it becomes very slow and takes almost 1 min on my machine. (This is compiling with cargo run --release).
The code aims to open an external program, and loop over the output from that program.
let a = vec!["view", "-h"]; // Arguments to open process with
let mut child = Command::new("samtools").args(&a)
.stdout(Stdio::piped())
.spawn()
.unwrap();
let collect_pairs = HashMap::<&str, &str>::new();
if let Some(ref mut stdout) = child.stdout {
for line in BufReader::new(stdout).lines() {
// Do stuff here
let name = "random";
if !collect_pairs.contains_key(&name) {
// Do nothing
}
}
}
For some reason adding the if !collect_pairs.contains_key( line increases the run time by almost a minute. The output from child is around 5 million lines. All this code exists in fn main()
EDIT
This appears to fix the problem, resulting in a fast run time, but I do not know why the !hashmap.contains_key does not work well here:
let n: Option<&&str> = collect_pairs.get(name);
if match n {Some(v) => 1, None => 0} == 1 {
// Do something
}
One thing to consider is that HashMap<K, V> uses a cryptographically secure hashing algorithm by default, so it will always be a bit slow by nature.
get() boils down to
self.search(k).map(|bucket| bucket.into_refs().1)
contains_key is
self.search(k).is_some()
As such, that get() is faster for you seems strange to me, it's doing more work!
Also,
if match n {Some(v) => 1, None => 0} == 1 {
This can be written more idiomatically as
if let Some(v) = n {
Ive found my problem, Im sorry I didnt pick up until now. I wasnt checking the return of if !collect_pairs.contains_key(&name) properly. It returns true for some reason resulting in the rest of the if block being run. I assumed it was evaluating to false. Thanks for the help