Skip to content

Commit

Permalink
feat(node): Add node_reward_type field to AddNodePayload and node con…
Browse files Browse the repository at this point in the history
…fig (#3116)

* Introduce the `node_reward_type`, to the node configuration and
`AddNodePayload` structures.
* Update related comments and scripts.
  • Loading branch information
sasa-tomic authored Dec 20, 2024
1 parent 4cb9765 commit c0132ba
Show file tree
Hide file tree
Showing 18 changed files with 139 additions and 25 deletions.
22 changes: 20 additions & 2 deletions ic-os/components/ic/generate-ic-config/generate-ic-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
function usage() {
cat <<EOF
Usage:
generate-ic-config [-n network.conf] [-c nns.conf] [-b backup.conf] [-m malicious_behavior.conf] [-q query_stats.conf] -i ic.json5.template -o ic.json5
generate-ic-config [-n network.conf] [-c nns.conf] [-b backup.conf] [-m malicious_behavior.conf] [-q query_stats.conf] [ -r reward.conf ] -i ic.json5.template -o ic.json5
Generate replica config from template file.
Expand All @@ -15,6 +15,7 @@ Usage:
-b backup.conf: Optional, parameters of the artifact backup
-m malicious_behavior.conf: Optional, malicious behavior parameters
-q query_stats.conf: Optional, query statistics epoch length configuration
-r reward.conf: Optional, node reward type configuration
-t jaeger_addr.conf: Optional, Jaeger address
-i infile: input ic.json5.template file
-o outfile: output ic.json5 file
Expand Down Expand Up @@ -139,6 +140,15 @@ function read_query_stats_variables() {
done <"$1"
}

# Read node reward type config variables from file. The file contains a single value which is the node reward type.
function read_node_reward_type_variable() {
while IFS="=" read -r key value; do
case "$key" in
"node_reward_type") node_reward_type="${value}" ;;
esac
done <"$1"
}

# Read Jaeger address variable from file. The file contains a single value Jaeger node address used in system tests.
function read_jaeger_addr_variable() {
while IFS="=" read -r key value; do
Expand All @@ -148,7 +158,7 @@ function read_jaeger_addr_variable() {
done <"$1"
}

while getopts "l:m:q:n:c:t:i:o:b:" OPT; do
while getopts "l:m:q:r:n:c:t:i:o:b:" OPT; do
case "${OPT}" in
n)
NETWORK_CONFIG_FILE="${OPTARG}"
Expand All @@ -165,6 +175,9 @@ while getopts "l:m:q:n:c:t:i:o:b:" OPT; do
q)
QUERY_STATS_CONFIG_FILE="${OPTARG}"
;;
r)
NODE_REWARD_TYPE="${OPTARG}"
;;
t)
JAEGER_ADDR_FILE="${OPTARG}"
;;
Expand Down Expand Up @@ -206,6 +219,10 @@ if [ "${QUERY_STATS_CONFIG_FILE}" != "" -a -e "${QUERY_STATS_CONFIG_FILE}" ]; th
read_query_stats_variables "${QUERY_STATS_CONFIG_FILE}"
fi

if [ "${NODE_REWARD_TYPE}" != "" -a -e "${NODE_REWARD_TYPE}" ]; then
read_node_reward_type_variable "${NODE_REWARD_TYPE}"
fi

if [ "${JAEGER_ADDR_FILE}" != "" -a -e "${JAEGER_ADDR_FILE}" ]; then
read_jaeger_addr_variable "${JAEGER_ADDR_FILE}"
fi
Expand Down Expand Up @@ -249,6 +266,7 @@ sed -e "s@{{ ipv6_address }}@${IPV6_ADDRESS}@" \
-e "s@{{ backup_purging_interval_secs }}@${BACKUP_PURGING_INTERVAL_SECS}@" \
-e "s@{{ malicious_behavior }}@${MALICIOUS_BEHAVIOR}@" \
-e "s@{{ query_stats_epoch_length }}@${QUERY_STATS_EPOCH_LENGTH}@" \
-e "s@{{ node_reward_type }}@${NODE_REWARD_TYPE}@" \
-e "s@{{ jaeger_addr }}@${JAEGER_ADDR}@" \
"${IN_FILE}" >"${OUT_FILE}"

Expand Down
1 change: 1 addition & 0 deletions ic-os/components/ic/generate-ic-config/ic.json5.template
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ table ip6 filter {\n\
},

registration: {
node_reward_type: "{{ node_reward_type }}",
nns_url: "{{ nns_urls }}",
nns_pub_key_pem: "/var/lib/ic/data/nns_public_key.pem",
node_operator_pem: "/var/lib/ic/data/node_operator_private_key.pem"
Expand Down
3 changes: 2 additions & 1 deletion ic-os/components/setupos-scripts/check-hardware.sh
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@ function read_variables() {
function validate_node_reward() {
read_variables
if [[ -z "$node_reward_type" ]]; then
log_and_halt_installation_on_error 1 "Configuration error: node_reward_type is not set"
echo "Node reward type is not set. Skipping validation."
return 0
fi

if [[ ! "$node_reward_type" =~ ^type[0-9]+(\.[0-9])?$ ]]; then
Expand Down
2 changes: 1 addition & 1 deletion ic-os/docs/Configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In production, configuration is propagated from a partition on the USB installer
=== SetupOS -> HostOS

SetupOS validates, sanitizes, and copies all of its configuration files to the HostOS config partition:
config.ini # Data center-specific network settings
config.ini # Data center and node-specific network settings
ssh_authorized_keys # SSH private keys
node_operator_private_key.pem # Node Operator private key created in the Node Provider onboarding
deployment.json # Deployment-specific configurations
Expand Down
4 changes: 2 additions & 2 deletions ic-os/setupos/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ The sequence of the scripts is defined in the main installation script, `setupos
== Node Providers, Node Technicians, and Node Operators

* *Node Provider*: An entity that purchases and owns the node hardware. Node Providers are rewarded for their node's useful work.
* *Node Technician*: These are the 'hired hands' or 'remote hands' employed by the Node Providers to maintain and manage the node. They do not necessarily own the hardware, but are responsible for its operation. Note that a single node will often have more than one Node Technicianthe Node Technician can be thought of as the individual currently operating the node, so this role can cycle among several parties.
** Note: While it is possible, it is uncommon for a Node Provider to also act as their own Node Technician.
* *Node Technician*: Node Technicians are responsible for the physical installation, maintenance, and repair of the node. These are typically 'hired hands' or 'remote hands' employed by the Node Providers to maintain and manage the node. A single node may have more than one Node Technicianthe Node Technician can be thought of as the individual currently operating the node, so this role can cycle among several parties. The information about the Node Technician is currently not stored in the NNS.
** Note: It is possible that a Node Provider and Node Technician are the same entity.
* *Node Operator*:
** The term "Node Operator" refers not to a specific individual or group, but to:
*** A specific record within the NNS registry—the *Node Operator record*, and to:
Expand Down
22 changes: 12 additions & 10 deletions ic-os/setupos/config/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@
#
# Update these settings according to your specific network and node requirements.

# ------------------------------
# Node Reward Settings (required)
# ------------------------------
# Update node_reward_type as per your node configuration.
# Node rewards setting should be of the form:
# node_reward_type=typeX or node_reward_type=typeX.Y
# Example:
# node_reward_type=type3.1
node_reward_type=

# ------------------------------
# IPv6 Settings (required)
# ------------------------------
Expand All @@ -23,6 +13,18 @@ ipv6_prefix=2a00:fb01:400:44
# Define the gateway address for your IPv6 network. Ensure it's within your network range:
ipv6_gateway=2a00:fb01:400:44::1

# ------------------------------
# Node Reward Settings (Required for the ICP Mainnet)
# -----------------------------
#
# Defines the node reward type that the operator expects for this node.
# The value must correspond to a community-approved type and operator configuration in the NNS.
# See https://wiki.internetcomputer.org/wiki/Node_Deployment_config.ini#node_reward_type_Documentation for more info.
#
# To find the rewardable node types for the node operator, run:
# ic-admin --nns-url https://ic0.app get-node-operator <operator-id>
#
# node_reward_type=type3.1

# ------------------------------
# IPv4 Settings (Optional)
Expand Down
5 changes: 5 additions & 0 deletions rs/config/src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ pub struct Config {

/// If this Sec256k1 PEM is available, use it instead of the HSM.
pub node_operator_pem: Option<PathBuf>,

/// Specifies the type of node rewards that the node operator expects to receive.
/// Examples include "type3.1" or "type1", corresponding to entries in the node rewards table in the NNS.
pub node_reward_type: Option<String>,
}

// We allow for the operator to only specify some of the fields while the others
Expand Down Expand Up @@ -57,6 +61,7 @@ impl Default for Config {
nns_url: None,
nns_pub_key_pem: None,
node_operator_pem: None,
node_reward_type: None,
}
}
}
1 change: 1 addition & 0 deletions rs/ic_os/dev_test_tools/launch-single-vm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ fn main() {
node_operator_principal_id: None,
secret_key_store: None,
domain: None,
node_reward_type: None,
},
)]);

Expand Down
15 changes: 11 additions & 4 deletions rs/orchestrator/src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,17 @@ impl NodeRegistration {
.expect("Invalid IPv4 configuration"),
domain: process_domain_name(&self.log, &self.node_config.domain)
.expect("Domain name is invalid"),
// Unused section follows
p2p_flow_endpoints: Default::default(),
prometheus_metrics_endpoint: Default::default(),
node_reward_type: None,
node_reward_type: if self.node_config.registration.node_reward_type.as_deref()
== Some("")
{
None
} else {
self.node_config.registration.node_reward_type.clone()
},

// The following fields are unused.
p2p_flow_endpoints: Default::default(), // unused field
prometheus_metrics_endpoint: Default::default(), // unused field
}
}

Expand Down
1 change: 1 addition & 0 deletions rs/prep/src/bin/prep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ mod test_flag_node_parser {
node_operator_principal_id: None,
secret_key_store: None,
domain: None,
node_reward_type: None,
},
};

Expand Down
13 changes: 12 additions & 1 deletion rs/prep/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ use ic_crypto_node_key_validation::ValidNodePublicKeys;
use ic_interfaces_state_manager::{CertificationScope, StateHashError, StateManager};
use ic_protobuf::registry::{
crypto::v1::{PublicKey, X509PublicKeyCert},
node::v1::{ConnectionEndpoint as pbConnectionEndpoint, NodeRecord as pbNodeRecord},
node::v1::{
ConnectionEndpoint as pbConnectionEndpoint, NodeRecord as pbNodeRecord, NodeRewardType,
},
};
use ic_registry_keys::{make_crypto_node_key, make_crypto_tls_cert_key, make_node_record_key};
use ic_registry_proto_data_provider::ProtoRegistryDataProvider;
Expand Down Expand Up @@ -306,6 +308,10 @@ pub struct NodeConfiguration {
/// The domain name of the node
#[serde(skip_serializing, skip_deserializing)]
pub domain: Option<String>,

/// The type of rewards that the node operator wants to receive for the node.
/// E.g. "type3.1" or "type1" or similar from the node reward table in the NNS.
pub node_reward_type: Option<String>,
}

impl From<NodeConfiguration> for pbNodeRecord {
Expand All @@ -324,6 +330,10 @@ impl From<NodeConfiguration> for pbNodeRecord {
.map(|id| id.to_vec())
.unwrap_or_default(),
domain: node_configuration.domain,
node_reward_type: node_configuration
.node_reward_type
.map(NodeRewardType::from)
.map(|t| t as i32),
..Default::default()
}
}
Expand Down Expand Up @@ -440,6 +450,7 @@ mod node_configuration {
node_operator_principal_id: None,
secret_key_store: None,
domain: None,
node_reward_type: None,
};

let got = pbNodeRecord::from(node_configuration);
Expand Down
1 change: 1 addition & 0 deletions rs/prep/src/prep_state_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ mod tests {
node_operator_principal_id: None,
secret_key_store: None,
domain: None,
node_reward_type: None,
},
);

Expand Down
22 changes: 21 additions & 1 deletion rs/protobuf/src/registry/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,30 @@ impl From<NodeRewardType> for String {
}
NodeRewardType::Type0 => "type0".to_string(),
NodeRewardType::Type1 => "type1".to_string(),
NodeRewardType::Type1dot1 => "type1.1".to_string(),
NodeRewardType::Type2 => "type2".to_string(),
NodeRewardType::Type3 => "type3".to_string(),
NodeRewardType::Type3dot1 => "type3.1".to_string(),
NodeRewardType::Type1dot1 => "type1.1".to_string(),
}
}
}

impl std::fmt::Display for NodeRewardType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", String::from(*self))
}
}

impl From<String> for NodeRewardType {
fn from(value: String) -> Self {
match value.as_str() {
"type0" => NodeRewardType::Type0,
"type1" => NodeRewardType::Type1,
"type1.1" => NodeRewardType::Type1dot1,
"type2" => NodeRewardType::Type2,
"type3" => NodeRewardType::Type3,
"type3.1" => NodeRewardType::Type3dot1,
_ => NodeRewardType::Unspecified,
}
}
}
48 changes: 45 additions & 3 deletions rs/registry/admin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ use ic_protobuf::registry::{
crypto::v1::{PublicKey, X509PublicKeyCert},
dc::v1::{AddOrRemoveDataCentersProposalPayload, DataCenterRecord},
firewall::v1::{FirewallConfig, FirewallRule, FirewallRuleSet},
node::v1::NodeRecord,
node::v1::{NodeRecord, NodeRewardType},
node_operator::v1::{NodeOperatorRecord, RemoveNodeOperatorsPayload},
node_rewards::v2::{NodeRewardRate, UpdateNodeRewardsTableProposalPayload},
provisional_whitelist::v1::ProvisionalWhitelist as ProvisionalWhitelistProto,
Expand All @@ -99,8 +99,8 @@ use ic_registry_keys::{
make_node_operator_record_key, make_node_record_key, make_provisional_whitelist_record_key,
make_replica_version_key, make_routing_table_record_key, make_subnet_list_record_key,
make_subnet_record_key, make_unassigned_nodes_config_record_key, FirewallRulesScope,
API_BOUNDARY_NODE_RECORD_KEY_PREFIX, NODE_OPERATOR_RECORD_KEY_PREFIX, NODE_REWARDS_TABLE_KEY,
ROOT_SUBNET_ID_KEY,
API_BOUNDARY_NODE_RECORD_KEY_PREFIX, NODE_OPERATOR_RECORD_KEY_PREFIX, NODE_RECORD_KEY_PREFIX,
NODE_REWARDS_TABLE_KEY, ROOT_SUBNET_ID_KEY,
};
use ic_registry_local_store::{
Changelog, ChangelogEntry, KeyMutation, LocalStoreImpl, LocalStoreWriter,
Expand Down Expand Up @@ -5090,6 +5090,48 @@ async fn print_and_get_last_value<T: Message + Default + serde::Serialize>(
record,
as_json,
);
} else if key.starts_with(NODE_RECORD_KEY_PREFIX.as_bytes()) {
#[derive(Debug, Serialize)]
pub struct Node {
pub xnet: Option<String>,
pub http: Option<String>,
pub node_operator_id: PrincipalId,
pub chip_id: Option<String>,
pub hostos_version_id: Option<String>,
pub public_ipv4_config: Option<String>,
pub domain: Option<String>,
pub node_reward_type: Option<String>,
}
let record =
NodeRecord::decode(&bytes[..]).expect("Error decoding value from registry.");
let record = Node {
xnet: record.xnet.map(|v| format!("[{}]:{}", v.ip_addr, v.port)),
http: record.http.map(|v| format!("[{}]:{}", v.ip_addr, v.port)),
node_operator_id: PrincipalId::try_from(record.node_operator_id)
.expect("Error decoding principal"),
chip_id: record.chip_id.map(hex::encode),
hostos_version_id: record.hostos_version_id,
public_ipv4_config: record.public_ipv4_config.map(|v| {
format!(
"ip_addr {} gw {:#?} prefix_length {}",
v.ip_addr, v.gateway_ip_addr, v.prefix_length
)
}),
domain: record.domain,
node_reward_type: record.node_reward_type.map(|t: i32| {
NodeRewardType::try_from(t)
.expect("Invalid node_reward_type value")
.to_string()
}),
};
print_value(
&std::str::from_utf8(&key)
.expect("key is not a str")
.to_string(),
version,
record,
as_json,
);
} else {
let value = T::decode(&bytes[..]).expect("Error decoding value from registry.");
print_value(
Expand Down
1 change: 1 addition & 0 deletions rs/registry/regedit/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ pub fn run_ic_prep() -> (TempDir, IcPrepStateDir) {
node_operator_principal_id: None,
secret_key_store: None,
domain: None,
node_reward_type: None,
},
);

Expand Down
1 change: 1 addition & 0 deletions rs/replica_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ pub fn get_ic_config() -> IcConfig {
node_operator_principal_id: None,
secret_key_store: Some(node_sks),
domain: None,
node_reward_type: None,
},
);

Expand Down
1 change: 1 addition & 0 deletions rs/starter/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ fn main() -> Result<()> {
node_operator_principal_id: None,
secret_key_store: None,
domain: None,
node_reward_type: None,
},
);

Expand Down
1 change: 1 addition & 0 deletions rs/tests/driver/src/driver/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ fn node_to_config(node: &Node) -> NodeConfiguration {
node_operator_principal_id: None,
secret_key_store: node.secret_key_store.clone(),
domain: node.domain.clone(),
node_reward_type: None,
}
}

Expand Down

0 comments on commit c0132ba

Please sign in to comment.