Skip to content

Commit

Permalink
fix(iota): fix DisplayMetadata when validator is pending (#3611)
Browse files Browse the repository at this point in the history
* fix(iota): fix DisplayMetadata when validator is pending, add test_become_validator

* fix error message, remove unused imports

* Update crates/iota/src/validator_commands.rs

Co-authored-by: DaughterOfMars <[email protected]>

* Add comments and use result

---------

Co-authored-by: DaughterOfMars <[email protected]>
  • Loading branch information
Thoralf-M and DaughterOfMars authored Oct 28, 2024
1 parent 9170764 commit fe0d82c
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 20 deletions.
110 changes: 108 additions & 2 deletions crates/iota/src/unit_tests/validator_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::{str::FromStr, time::Duration};

use anyhow::Ok;
use fastcrypto::encoding::{Base64, Encoding};
use iota_json::IotaJsonValue;
use iota_types::{
base_types::IotaAddress,
crypto::{IotaKeyPair, Signature},
transaction::{Transaction, TransactionData},
};
use shared_crypto::intent::{Intent, IntentMessage};
use tempfile::TempDir;
use test_cluster::TestClusterBuilder;
use tokio::time::sleep;

use crate::validator_commands::{
IotaValidatorCommand, IotaValidatorCommandResponse, get_validator_summary,
use crate::{
client_commands::{IotaClientCommandResult, IotaClientCommands, OptsWithGas},
validator_commands::{
IotaValidatorCommand, IotaValidatorCommandResponse, get_validator_summary,
},
};

#[tokio::test]
Expand Down Expand Up @@ -69,3 +77,101 @@ async fn test_print_raw_rgp_txn() -> Result<(), anyhow::Error> {
assert_eq!(summary.next_epoch_gas_price, 42);
Ok(())
}

#[tokio::test]
async fn test_become_validator() -> Result<(), anyhow::Error> {
cleanup_fs();
let config_dir = TempDir::new().unwrap();

let test_cluster = TestClusterBuilder::new()
.with_config_dir(config_dir.path().to_path_buf())
.build()
.await;

let mut context = test_cluster.wallet;
let address = context.active_address()?;
let client = context.get_client().await?;

let response = IotaValidatorCommand::MakeValidatorInfo {
name: "validator0".to_string(),
description: "description".to_string(),
image_url: "https://iota.org/logo.png".to_string(),
project_url: "https://www.iota.org".to_string(),
host_name: "127.0.0.1".to_string(),
gas_price: 1000,
}
.execute(&mut context)
.await?;
let IotaValidatorCommandResponse::MakeValidatorInfo = response else {
panic!("Expected MakeValidatorInfo");
};

let response = IotaValidatorCommand::BecomeCandidate {
file: "validator.info".into(),
gas_budget: None,
}
.execute(&mut context)
.await?;
let IotaValidatorCommandResponse::BecomeCandidate(_become_candidate_tx) = response else {
panic!("Expected BecomeCandidate");
};
// Wait some time to be sure that the tx is executed
sleep(Duration::from_secs(2)).await;

// Get coin and stake
let coins = client
.coin_read_api()
.get_coins(address, None, None, None)
.await?;
let stake_result = IotaClientCommands::Call {
package: "0x3".parse()?,
module: "iota_system".to_string(),
function: "request_add_stake".to_string(),
type_args: vec![],
gas_price: None,
args: vec![
IotaJsonValue::from_str("0x5").unwrap(),
IotaJsonValue::from_str(&coins.data.first().unwrap().coin_object_id.to_string())
.unwrap(),
IotaJsonValue::from_str(&address.to_string()).unwrap(),
],
opts: OptsWithGas::for_testing(None, 1000000000),
}
.execute(&mut context)
.await?;
let IotaClientCommandResult::TransactionBlock(_) = stake_result else {
panic!("Expected TransactionBlock");
};
// Wait some time to be sure that the tx is executed
sleep(Duration::from_secs(2)).await;

let response = IotaValidatorCommand::JoinCommittee { gas_budget: None }
.execute(&mut context)
.await?;
let IotaValidatorCommandResponse::JoinCommittee(_tx) = response else {
panic!("Expected JoinCommittee");
};
sleep(Duration::from_secs(2)).await;

let response = IotaValidatorCommand::DisplayMetadata {
validator_address: None,
json: None,
}
.execute(&mut context)
.await?;
let IotaValidatorCommandResponse::DisplayMetadata = response else {
panic!("Expected DisplayMetadata");
};

cleanup_fs();
// These files get generated in IotaValidatorCommand::MakeValidatorInfo in the
// current directory, so we have to clean them up
fn cleanup_fs() {
std::fs::remove_file("validator.info").ok();
std::fs::remove_file("account.key").ok();
std::fs::remove_file("authority.key").ok();
std::fs::remove_file("protocol.key").ok();
std::fs::remove_file("network.key").ok();
}
Ok(())
}
25 changes: 9 additions & 16 deletions crates/iota/src/validator_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use iota_types::{
IotaKeyPair, NetworkKeyPair, NetworkPublicKey, Signable, SignatureScheme,
generate_proof_of_possession, get_authority_key_pair,
},
dynamic_field::Field,
iota_system_state::{
iota_system_state_inner_v1::{UnverifiedValidatorOperationCap, ValidatorV1},
iota_system_state_summary::{IotaSystemStateSummary, IotaValidatorSummary},
Expand Down Expand Up @@ -1108,16 +1109,13 @@ async fn display_metadata(
json: bool,
) -> anyhow::Result<()> {
match get_validator_summary(client, validator_address).await? {
None => println!(
"{} is not an active or pending Validator.",
validator_address
),
None => println!("{validator_address} is not an active or pending Validator"),
Some((status, info)) => {
println!("{}'s valdiator status: {:?}", validator_address, status);
println!("{validator_address}'s validator status: {status:?}");
if json {
println!("{}", serde_json::to_string_pretty(&info)?);
} else {
println!("{:#?}", info);
println!("{info:#?}");
}
}
}
Expand Down Expand Up @@ -1149,20 +1147,15 @@ async fn get_pending_candidate_summary(
// included.
let object_id = resp.object_id()?;
let bcs = resp.move_object_bcs().ok_or_else(|| {
anyhow::anyhow!(
"Object {} does not exist or does not return bcs bytes",
object_id
)
anyhow::anyhow!("Object {object_id} does not exist or does not return bcs bytes",)
})?;
let val = bcs::from_bytes::<ValidatorV1>(bcs).map_err(|e| {
let field = bcs::from_bytes::<Field<u64, ValidatorV1>>(bcs).map_err(|e| {
anyhow::anyhow!(
"Can't convert bcs bytes of object {} to ValidatorV1: {}",
object_id,
e,
"Can't convert bcs bytes of object {object_id} to Field<u64, ValidatorV1>: {e}",
)
})?;
if val.verified_metadata().iota_address == validator_address {
return Ok(Some(val));
if field.value.verified_metadata().iota_address == validator_address {
return Ok(Some(field.value));
}
}
Ok(None)
Expand Down
2 changes: 1 addition & 1 deletion iota-execution/latest/iota-move-natives/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn validate_metadata_bcs(
let validator_metadata =
bcs::from_bytes::<ValidatorMetadataV1>(&metadata_bytes).map_err(|_| {
PartialVMError::new(StatusCode::MALFORMED).with_message(
"ValidateMetadata Move struct does not much internal ValidateMetadata struct"
"ValidatorMetadata Move struct does not match internal ValidatorMetadataV1 struct"
.to_string(),
)
})?;
Expand Down
2 changes: 1 addition & 1 deletion iota-execution/v0/iota-move-natives/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn validate_metadata_bcs(
let validator_metadata =
bcs::from_bytes::<ValidatorMetadataV1>(&metadata_bytes).map_err(|_| {
PartialVMError::new(StatusCode::MALFORMED).with_message(
"ValidateMetadata Move struct does not much internal ValidateMetadata struct"
"ValidatorMetadata Move struct does not match internal ValidatorMetadataV1 struct"
.to_string(),
)
})?;
Expand Down
26 changes: 26 additions & 0 deletions nre/validator_tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,29 @@ iota client call --package 0x3 --module iota_system --function request_add_stake
```bash
iota validator join-committee
```

#### Combined

First terminal:

```bash
iota start --force-regenesis --with-faucet --faucet-amount 2600000000000000
```

Second terminal after the faucet is up:

```bash
iota client switch --env localnet
iota client faucet --url http://127.0.0.1:9123/gas
sleep 2
iota validator make-validator-info validator0 description https://iota.org/logo.png https://www.iota.org 127.0.0.1 1000
iota validator become-candidate validator.info
sleep 2
coinObjectId=$(iota client gas --json | jq '.[0].gasCoinId')
validatorAddress=$(iota client active-address)
iota client call --package 0x3 --module iota_system --function request_add_stake --args 0x5 $coinObjectId $validatorAddress --gas-budget 10000000
sleep 2
iota validator join-committee
sleep 2
iota validator display-metadata
```

0 comments on commit fe0d82c

Please sign in to comment.