From 07d374d5d144e7da123f0d584ce0eac816a94d89 Mon Sep 17 00:00:00 2001 From: mlbones666 <127071266+mlbones666@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:26:54 +0800 Subject: [PATCH 01/32] update version of mev-boost --- docker-compose-operator-mev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose-operator-mev.yml b/docker-compose-operator-mev.yml index dd1370a..2a34d12 100644 --- a/docker-compose-operator-mev.yml +++ b/docker-compose-operator-mev.yml @@ -37,7 +37,7 @@ services: - "30303" mev-boost: - image: flashbots/mev-boost:1.6.1a3 + image: flashbots/mev-boost:1.7 network_mode: "host" pull_policy: always restart: unless-stopped From eb4259dc1501f0836ac0a55d84c7f7f0e5d9db4e Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Mon, 26 Aug 2024 16:04:13 +0000 Subject: [PATCH 02/32] add not leader error handle --- src/validation/block_service.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/validation/block_service.rs b/src/validation/block_service.rs index e1ff3db..80d1dd7 100644 --- a/src/validation/block_service.rs +++ b/src/validation/block_service.rs @@ -8,6 +8,7 @@ use crate::validation::{ use crate::validation::{ http_metrics::metrics, validator_store::Error as ValidatorStoreError, validator_store::ValidatorStore, + signing_method::Error as SigningError }; use bls::SignatureBytes; use environment::RuntimeContext; @@ -572,6 +573,9 @@ impl BlockService { let signed_block = match res { Ok(block) => block, + Err(ValidatorStoreError::UnableToSign(SigningError::NotLeader)) => { + return Ok(()); + } Err(ValidatorStoreError::UnknownPubkey(pubkey)) => { // A pubkey can be missing when a validator was recently removed // via the API. From de3edcd863c063d1ca71174b4f8d707e5d7d07ea Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Wed, 28 Aug 2024 03:15:02 +0000 Subject: [PATCH 03/32] add log --- src/validation/block_service.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/validation/block_service.rs b/src/validation/block_service.rs index 80d1dd7..abea7bc 100644 --- a/src/validation/block_service.rs +++ b/src/validation/block_service.rs @@ -888,14 +888,27 @@ impl BlockService { })?; let unsigned_block = match block_response.data { - eth2::types::ProduceBlockV3Response::Full(block) => UnsignedBlock::Full(block), - eth2::types::ProduceBlockV3Response::Blinded(block) => UnsignedBlock::Blinded(block), + eth2::types::ProduceBlockV3Response::Full(block) => { + info!( + log, + "Received unsigned block"; + "block hash" => ?block.block().state_root() + ); + UnsignedBlock::Full(block) + }, + eth2::types::ProduceBlockV3Response::Blinded(block) => { + info!( + log, + "Received unsigned block"; + "block hash" => ?block.state_root() + ); + UnsignedBlock::Blinded(block) + } }; - info!( log, "Received unsigned block"; - "slot" => slot.as_u64(), + "slot" => slot.as_u64() ); if proposer_index != Some(unsigned_block.proposer_index()) { return Err(BlockError::Recoverable( From d38f3e6a4fe3bcdc8f8561d0dc5c4e3f00355faf Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Wed, 28 Aug 2024 03:54:59 +0000 Subject: [PATCH 04/32] add log --- src/validation/block_service.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation/block_service.rs b/src/validation/block_service.rs index abea7bc..70749c5 100644 --- a/src/validation/block_service.rs +++ b/src/validation/block_service.rs @@ -891,7 +891,7 @@ impl BlockService { eth2::types::ProduceBlockV3Response::Full(block) => { info!( log, - "Received unsigned block"; + "Received unsigned full block"; "block hash" => ?block.block().state_root() ); UnsignedBlock::Full(block) @@ -899,7 +899,7 @@ impl BlockService { eth2::types::ProduceBlockV3Response::Blinded(block) => { info!( log, - "Received unsigned block"; + "Received unsigned blinded block"; "block hash" => ?block.state_root() ); UnsignedBlock::Blinded(block) From 8455eda849db6c0cc66a0ee9dad5d3e9c6a00a44 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Wed, 28 Aug 2024 04:09:02 +0000 Subject: [PATCH 05/32] add log --- src/validation/block_service.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/validation/block_service.rs b/src/validation/block_service.rs index 70749c5..4067a64 100644 --- a/src/validation/block_service.rs +++ b/src/validation/block_service.rs @@ -891,7 +891,7 @@ impl BlockService { eth2::types::ProduceBlockV3Response::Full(block) => { info!( log, - "Received unsigned full block"; + "Received unsigned full block v3"; "block hash" => ?block.block().state_root() ); UnsignedBlock::Full(block) @@ -899,7 +899,7 @@ impl BlockService { eth2::types::ProduceBlockV3Response::Blinded(block) => { info!( log, - "Received unsigned blinded block"; + "Received unsigned blinded block v3"; "block hash" => ?block.state_root() ); UnsignedBlock::Blinded(block) @@ -964,6 +964,23 @@ impl BlockService { ) }; + match &unsigned_block { + UnsignedBlock::Blinded(block) => { + info!( + log, + "Received unsigned full block"; + "block hash" => ?block.state_root() + ); + }, + UnsignedBlock::Full(block) => { + info!( + log, + "Received unsigned full block"; + "block hash" => ?block.block().state_root() + ); + } + } + info!( log, "Received unsigned block"; From 6aa61219f90a094f5297bed7bda4110dbd00da70 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Wed, 28 Aug 2024 10:23:16 +0000 Subject: [PATCH 06/32] add graffiti --- src/validation/block_service.rs | 50 ++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/validation/block_service.rs b/src/validation/block_service.rs index 4067a64..be738af 100644 --- a/src/validation/block_service.rs +++ b/src/validation/block_service.rs @@ -2,7 +2,6 @@ use crate::validation::beacon_node_fallback::{Error as FallbackError, Errors}; use crate::validation::{ beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}, - determine_graffiti, graffiti_file::GraffitiFile, }; use crate::validation::{ @@ -23,7 +22,7 @@ use std::sync::Arc; use std::time::Duration; use tokio::sync::mpsc; use types::{ - BlindedBeaconBlock, BlockType, EthSpec, Graffiti, PublicKeyBytes, SignedBlindedBeaconBlock, + BlindedBeaconBlock, BlockType, EthSpec, Graffiti, GRAFFITI_BYTES_LEN, PublicKeyBytes, SignedBlindedBeaconBlock, Slot, }; @@ -471,13 +470,23 @@ impl BlockService { } }; - let graffiti = determine_graffiti( - &validator_pubkey, - log, - self.graffiti_file.clone(), - self.validator_store.graffiti(&validator_pubkey).await, - self.graffiti, - ); + // let graffiti = determine_graffiti( + // &validator_pubkey, + // log, + // self.graffiti_file.clone(), + // self.validator_store.graffiti(&validator_pubkey).await, + // self.graffiti, + // ); + + let graffiti = Some({ + let graffiti_str = "SafeStake Operator"; + let bytes = graffiti_str.as_bytes(); + let mut graffiti_bytes = [0u8; GRAFFITI_BYTES_LEN]; + for (i, byte) in bytes.iter().enumerate() { + graffiti_bytes[i] = *byte; + } + Graffiti::from(graffiti_bytes) + }); let randao_reveal_ref = &randao_reveal; let self_ref = &self; @@ -671,13 +680,22 @@ impl BlockService { } }; - let graffiti = determine_graffiti( - &validator_pubkey, - log, - self.graffiti_file.clone(), - self.validator_store.graffiti(&validator_pubkey).await, - self.graffiti, - ); + // let graffiti = determine_graffiti( + // &validator_pubkey, + // log, + // self.graffiti_file.clone(), + // self.validator_store.graffiti(&validator_pubkey).await, + // self.graffiti, + // ); + let graffiti = Some({ + let graffiti_str = "SafeStake Operator"; + let bytes = graffiti_str.as_bytes(); + let mut graffiti_bytes = [0u8; GRAFFITI_BYTES_LEN]; + for (i, byte) in bytes.iter().enumerate() { + graffiti_bytes[i] = *byte; + } + Graffiti::from(graffiti_bytes) + }); let randao_reveal_ref = &randao_reveal; let self_ref = &self; From fe69e4518f3699dec7ae41384e9671394c710ab3 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Thu, 29 Aug 2024 03:22:04 +0000 Subject: [PATCH 07/32] add debug log --- src/validation/block_service.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/validation/block_service.rs b/src/validation/block_service.rs index be738af..54696fb 100644 --- a/src/validation/block_service.rs +++ b/src/validation/block_service.rs @@ -986,15 +986,17 @@ impl BlockService { UnsignedBlock::Blinded(block) => { info!( log, - "Received unsigned full block"; - "block hash" => ?block.state_root() + "Received unsigned blinded block"; + "block hash" => ?block.state_root(), + "block" => ?block ); }, UnsignedBlock::Full(block) => { info!( log, "Received unsigned full block"; - "block hash" => ?block.block().state_root() + "block hash" => ?block.block().state_root(), + "block" => ?block.block() ); } } From d73447c80233a8d5910515ff30ffa02b255ce06c Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Thu, 29 Aug 2024 13:22:46 +0000 Subject: [PATCH 08/32] use block v3 --- src/validation/validator_store.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/validation/validator_store.rs b/src/validation/validator_store.rs index 1ef7bef..4358d0c 100644 --- a/src/validation/validator_store.rs +++ b/src/validation/validator_store.rs @@ -343,7 +343,8 @@ impl ValidatorStore { } pub fn produce_block_v3(&self) -> bool { - self.produce_block_v3 + true + // self.produce_block_v3 } /// Returns a `SigningMethod` for `validator_pubkey` *only if* that validator is considered safe From ff7bbefe3ad254dc5c6a68012dd2dfaedac95f74 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Tue, 15 Oct 2024 09:31:08 +0000 Subject: [PATCH 09/32] add monitor tool --- src/bin/dvf_monitor_tool.rs | 97 +++++++++++++++++++++++++++++++++++++ src/node/config.rs | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/bin/dvf_monitor_tool.rs diff --git a/src/bin/dvf_monitor_tool.rs b/src/bin/dvf_monitor_tool.rs new file mode 100644 index 0000000..db690f5 --- /dev/null +++ b/src/bin/dvf_monitor_tool.rs @@ -0,0 +1,97 @@ +use network::{DvfMessage, ReliableSender}; +use dvf_version::VERSION; +use std::fs::File; +use dvf::node::config::{BOOT_ENRS_CONFIG_FILE, base_to_signature_addr, base_to_duties_addr, base_to_active_addr}; +use lighthouse_network::discv5::enr::{Enr, CombinedKey}; +use std::net::{IpAddr, SocketAddr}; +use bytes::Bytes; +use log::{error, info}; +use std::net::TcpStream; + +fn all_equal(array: &[T]) -> bool { + if let Some(first) = array.first() { + array.iter().all(|x| x == first) + } else { + true + } +} + +async fn query_socket_address_from_boot(enrs: Vec>, op_pk: Vec) -> Vec { + // query socket address of the operator + let dvf_message = DvfMessage { + version: VERSION, + validator_id: 0, + message: op_pk.clone(), + }; + let serialized_msg = bincode::serialize(&dvf_message).unwrap(); + let boot_socketaddrs: Vec = enrs.iter().map(|e| { + SocketAddr::new( + IpAddr::V4(e.ip4().expect("boot enr ip should not be empty")), + e.udp4().expect("boot enr port should not be empty")) + }).collect(); + let network_sender = ReliableSender::new(); + let mut result = Vec::new(); + for addr in boot_socketaddrs { + match network_sender + .send(addr, Bytes::from(serialized_msg.clone())) + .await.await { + Ok(data) => { + let op_base_socketaddr = bincode::deserialize::(&data).unwrap(); + result.push(op_base_socketaddr); + }, + Err(e) => { + error!("failed to query op socket addr from boot {}", e) + } + } + } + result +} + +fn check_all_ports(base_addr: SocketAddr) -> bool { + TcpStream::connect(base_to_signature_addr(base_addr)).is_ok() && + TcpStream::connect(base_to_duties_addr(base_addr)).is_ok() && + TcpStream::connect(base_to_active_addr(base_addr)).is_ok() +} + +#[tokio::main] +async fn main() { + let mut logger = + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")); + logger.format_timestamp_millis(); + logger.init(); + log::info!("------dvf_monitor_tool------"); + + let op_pk_str = std::env::args() + .nth(1) + .expect("ERROR: there is no valid operator public key argument"); + + let op_pk = hex::decode(&op_pk_str[2..]).expect("decode failed, op pk should be in hex format"); + + let file = File::options() + .read(true) + .write(false) + .create(false) + .open(BOOT_ENRS_CONFIG_FILE) + .expect( + format!( + "Unable to open the boot enrs config file: {:?}", + BOOT_ENRS_CONFIG_FILE + ) + .as_str(), + ); + let boot_enrs: Vec> = + serde_yaml::from_reader(file).expect("Unable to parse boot enr"); + + let op_addrs = query_socket_address_from_boot(boot_enrs, op_pk).await; + if op_addrs.is_empty() { + panic!("failed to query op socket address from boot node"); + } + if !all_equal(&op_addrs) { + panic!("the op addresses from different boot nodes are not same {:?}", op_addrs) + } + let base_addr = op_addrs.first().unwrap(); + if !check_all_ports(base_addr.clone()) { + panic!("ports checking failed") + } + info!("op {} is ready", op_pk_str); +} \ No newline at end of file diff --git a/src/node/config.rs b/src/node/config.rs index 489ef04..e08a0be 100644 --- a/src/node/config.rs +++ b/src/node/config.rs @@ -30,7 +30,7 @@ pub const VALIDATOR_PK_URL: &str = "validator_pk"; pub const PRESTAKE_SIGNATURE_URL: &str = "prestake_signature"; pub const STAKE_SIGNATURE_URL: &str = "stake_signature"; pub const TOPIC_NODE_INFO: &str = "dvf/topic_node_info"; -const BOOT_ENRS_CONFIG_FILE: &str = "boot_config/boot_enrs.yaml"; +pub const BOOT_ENRS_CONFIG_FILE: &str = "boot_config/boot_enrs.yaml"; lazy_static! { // [Issue] SocketAddr::new is not yet a const fn in stable release. From dbc3fa40c9ae2047dae883ccad1ba4de9ef02569 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Sun, 27 Oct 2024 14:51:52 +0000 Subject: [PATCH 10/32] add config contract --- .env.example | 1 + contract_config/configs.yml | 2 +- docker-compose-operator-mev.yml | 2 +- docker-compose-operator.yml | 2 +- src/bin/dvf_monitor_tool.rs | 1 + src/node/contract.rs | 60 +++++++--------------- src/node/db.rs | 90 +++++++++++++++++++++++++++++++++ src/node/node.rs | 2 + src/validation/cli.rs | 22 ++++---- src/validation/config.rs | 8 +-- 10 files changed, 130 insertions(+), 60 deletions(-) diff --git a/.env.example b/.env.example index 6ab7800..e63c5d0 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,7 @@ OPERATOR_NETWORK=mainnet IMAGE_TAG=v3.4.0-mainnet REGISTRY_CONTRACT_ADDRESS=1a1f82f0365571A0b06df0992FC4D1BCc5Fdc6aD NETWORK_CONTRACT_ADDRESS=829f3c089fE315FCB2BC9506B237BB56b7c3335B +CONFIG_CONTRACT_ADDRESS=1EFB8c90381695584CcB117388Bba897b71e0635 API_SERVER=https://api-node.safestake.xyz/api/op/ # different chain has different ttd TTD=10790000 diff --git a/contract_config/configs.yml b/contract_config/configs.yml index bf62d92..2e22bdb 100644 --- a/contract_config/configs.yml +++ b/contract_config/configs.yml @@ -5,6 +5,6 @@ initiator_registration_topic: 3ed0a993c042af686c0f93773269df3a1874729d2b4fc3f71f initiator_minipool_created_topic: d37d31a5a66d534ce3b071e3ee6cf8b7d36a6dd20aa4f08e9cec322b27bd7704 initiator_minipool_ready_topic: c474edb44e2d7e6c7f20261d61afed24712bcbd6a0799ae5b0786626c47da63c initiator_removal_topic: 34ecedfa430a18df6cda4bc2313d74d224c6742df8e6a98eca2fda96b69a050d -fee_recipient_set_topic: a2ae9b7eef58d6d2779721289e4e6fecb49b0134e40d787b3bed6743ed325497 +fee_recipient_set_topic: 05d899f2c039ff7edfb413f1f4fe82889c2efaace7f08d7ac5aebad905b27ced safestake_network_abi_path: contract_config/SafeStakeNetwork.json safestake_registry_abi_path: contract_config/SafeStakeRegistry.json diff --git a/docker-compose-operator-mev.yml b/docker-compose-operator-mev.yml index 8373377..04587ed 100644 --- a/docker-compose-operator-mev.yml +++ b/docker-compose-operator-mev.yml @@ -89,7 +89,7 @@ services: - /bin/sh - -c - | - dvf validator_client --builder-proposals --metrics --debug-level=info --network=${OPERATOR_NETWORK} --beacon-nodes=${BEACON_NODE_ENDPOINT} --api=${API_SERVER} --ws-url=${WS_URL} --ip=${NODE_IP} --id=${OPERATOR_ID} --registry-contract=${REGISTRY_CONTRACT_ADDRESS} --network-contract=${NETWORK_CONTRACT_ADDRESS} --base-port=26000 2>&1 + dvf validator_client --builder-proposals --metrics --debug-level=info --network=${OPERATOR_NETWORK} --beacon-nodes=${BEACON_NODE_ENDPOINT} --api=${API_SERVER} --ws-url=${WS_URL} --ip=${NODE_IP} --id=${OPERATOR_ID} --registry-contract=${REGISTRY_CONTRACT_ADDRESS} --network-contract=${NETWORK_CONTRACT_ADDRESS} --config-contract=${CONFIG_CONTRACT_ADDRESS} --base-port=26000 2>&1 expose: - "26000" - "26001" diff --git a/docker-compose-operator.yml b/docker-compose-operator.yml index 8bae598..26efde8 100644 --- a/docker-compose-operator.yml +++ b/docker-compose-operator.yml @@ -80,7 +80,7 @@ services: - /bin/sh - -c - | - dvf validator_client --metrics --debug-level=info --network=${OPERATOR_NETWORK} --beacon-nodes=${BEACON_NODE_ENDPOINT} --api=${API_SERVER} --ws-url=${WS_URL} --ip=${NODE_IP} --id=${OPERATOR_ID} --registry-contract=${REGISTRY_CONTRACT_ADDRESS} --network-contract=${NETWORK_CONTRACT_ADDRESS} --base-port=26000 2>&1 + dvf validator_client --metrics --debug-level=info --network=${OPERATOR_NETWORK} --beacon-nodes=${BEACON_NODE_ENDPOINT} --api=${API_SERVER} --ws-url=${WS_URL} --ip=${NODE_IP} --id=${OPERATOR_ID} --registry-contract=${REGISTRY_CONTRACT_ADDRESS} --network-contract=${NETWORK_CONTRACT_ADDRESS} --config-contract=${CONFIG_CONTRACT_ADDRESS} --base-port=26000 2>&1 expose: - "26000" - "26001" diff --git a/src/bin/dvf_monitor_tool.rs b/src/bin/dvf_monitor_tool.rs index db690f5..12caa81 100644 --- a/src/bin/dvf_monitor_tool.rs +++ b/src/bin/dvf_monitor_tool.rs @@ -83,6 +83,7 @@ async fn main() { serde_yaml::from_reader(file).expect("Unable to parse boot enr"); let op_addrs = query_socket_address_from_boot(boot_enrs, op_pk).await; + info!("node addre {:?}", op_addrs); if op_addrs.is_empty() { panic!("failed to query op socket address from boot node"); } diff --git a/src/node/contract.rs b/src/node/contract.rs index d6d1243..b3e6b8b 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -38,7 +38,7 @@ pub static SELF_OPERATOR_ID: OnceCell = OnceCell::const_new(); pub static DEFAULT_TRANSPORT_URL: OnceCell = OnceCell::const_new(); pub static REGISTRY_CONTRACT: OnceCell = OnceCell::const_new(); pub static NETWORK_CONTRACT: OnceCell = OnceCell::const_new(); -// pub static EXTRA_CONTRACT: OnceCell = OnceCell::const_new(); +pub static CONFIG_CONTRACT: OnceCell = OnceCell::const_new(); pub static DATABASE: OnceCell = OnceCell::const_new(); const QUERY_LOGS_INTERVAL: u64 = 60; const QUERY_BLOCK_INTERVAL: u64 = 500; @@ -455,7 +455,7 @@ impl Contract { let va_filter_builder = FilterBuilder::default() .address(vec![ Address::from_slice(&hex::decode(NETWORK_CONTRACT.get().unwrap()).unwrap()), - // Address::from_slice(&hex::decode(EXTRA_CONTRACT.get().unwrap()).unwrap()), + Address::from_slice(&hex::decode(CONFIG_CONTRACT.get().unwrap()).unwrap()), ]) .topics( Some(vec![va_reg_topic, va_rm_topic, fee_receipient_set_topic]), @@ -805,10 +805,16 @@ pub async fn process_validator_registration( .into_iter() .map(|s| base64::decode(s).unwrap()) .collect(); + let fee_recipient_address = match db.query_owner_fee_recipient(address.clone()).await.map_err(|_| { + ContractError::DatabaseError + })? { + Some(a) => a, + None => address + }; //send command to node let validator = Validator { id: validator_id, - owner_address: address, + owner_address: fee_recipient_address, public_key: va_pk.try_into().unwrap(), releated_operators: op_ids, active: true, @@ -1173,20 +1179,10 @@ pub async fn process_fee_recipient_set(raw_log: Log, db: &Database) -> Result<() indexed: true, }, EventParam { - name: "pubkey".to_string(), - kind: ParamType::Bytes, - indexed: false, - }, - EventParam { - name: "feeReceiptAddress".to_string(), + name: "newAddress".to_string(), kind: ParamType::Address, indexed: true, }, - EventParam { - name: "updateCount".to_string(), - kind: ParamType::Uint(32), - indexed: false, - }, ], anonymous: false, }; @@ -1201,39 +1197,19 @@ pub async fn process_fee_recipient_set(raw_log: Log, db: &Database) -> Result<() .clone() .into_address() .ok_or(ContractError::LogParseError)?; - let pubkey = log.params[1] - .value - .clone() - .into_bytes() - .ok_or(ContractError::LogParseError)?; - let fee_recipient_address = log.params[2] + let fee_recipient_address = log.params[1] .value .clone() .into_address() .ok_or(ContractError::LogParseError)?; - if pubkey.iter().all(|&x| x == 0) { - // public key is zero - for v in db.query_validator_by_address(owner).await.unwrap().iter() { - let cmd = ContractCommand::SetFeeRecipient(v.public_key.clone(), fee_recipient_address); - db.insert_contract_command(v.id, serde_json::to_string(&cmd).unwrap()) - .await; - } - } else { - match db - .query_validator_by_public_key(hex::encode(pubkey.clone())) - .await - .unwrap() - { - Some(v) => { - let cmd = ContractCommand::SetFeeRecipient(pubkey, fee_recipient_address); - db.insert_contract_command(v.id, serde_json::to_string(&cmd).unwrap()) - .await; - } - None => { - info!("set fee recipient not releated to this operator"); - } - } + db.upsert_owner_fee_recipient(owner, fee_recipient_address).await; + + // public key is zero + for v in db.query_validator_by_address(owner).await.unwrap().iter() { + let cmd = ContractCommand::SetFeeRecipient(v.public_key.clone(), fee_recipient_address); + db.insert_contract_command(v.id, serde_json::to_string(&cmd).unwrap()) + .await; } Ok(()) diff --git a/src/node/db.rs b/src/node/db.rs index 0f6309c..6cb7ef3 100644 --- a/src/node/db.rs +++ b/src/node/db.rs @@ -41,6 +41,8 @@ pub enum DbCommand { QueryInitiatorStore(u32, oneshot::Sender>>), QueryAllValidatorPublicKeys(oneshot::Sender>>), QueryValidatorRegistrationTimestamp(String, oneshot::Sender>), + UpsertOwnerFeeRecipient(Address, Address), + QueryOwnerFeeRecipient(Address, oneshot::Sender>>) } #[derive(Clone, Debug)] @@ -134,6 +136,11 @@ impl Database { CONSTRAINT initiator_store_constraint FOREIGN KEY (record_id) REFERENCES initiator_store_record(id) ON DELETE CASCADE )"; + let create_owner_fee_recipient_sql = "CREATE TABLE IF NOT EXISTS owner_fee_recipient( + owner CHARACTER(40) NOT NULL PRIMARY KEY, + fee_recipient CHARACTER(40) NOT NULL + )"; + conn.execute(create_operators_sql, [])?; conn.execute(create_validators_sql, [])?; conn.execute(create_releation_sql, [])?; @@ -145,6 +152,7 @@ impl Database { conn.execute(create_initiator_store_sql, [])?; conn.execute(create_initiator_store_oppk_sql, [])?; conn.execute(create_validators_registration_timestamp_sql, [])?; + conn.execute(create_owner_fee_recipient_sql, [])?; let (tx, mut rx) = channel(1000); tokio::spawn(async move { @@ -242,6 +250,13 @@ impl Database { query_validator_registration_timestamp(&mut conn, &public_key); let _ = sender.send(response); } + DbCommand::UpsertOwnerFeeRecipient(owner, fee_recipient) => { + upsert_owner_fee_recipient(&mut conn, owner, fee_recipient); + } + DbCommand::QueryOwnerFeeRecipient(owner, sender) => { + let response = query_owner_fee_recipient(&mut conn, owner); + let _ = sender.send(response); + } } } }); @@ -617,6 +632,37 @@ impl Database { .await .expect("Failed to receive reply of query validators registration timestamp from db") } + + pub async fn upsert_owner_fee_recipient( + &self, + owner: Address, + fee_recipient: Address + ) { + + if let Err(e) = self + .channel + .send(DbCommand::UpsertOwnerFeeRecipient(owner, fee_recipient)) + .await + { + panic!("Failed to send enable validator command to store: {}", e); + } + } + + pub async fn query_owner_fee_recipient( + &self, + owner: Address, + ) -> DbResult>{ + let (sender, receiver) = oneshot::channel(); + if let Err(e) = self.channel.send(DbCommand::QueryOwnerFeeRecipient(owner, sender)).await { + panic!( + "Failed to send query fee recipient address to store: {}", + e + ); + } + receiver + .await + .expect("Failed to receive reply of query fee recipient address from db") + } } fn insert_operator(conn: &Connection, operator: Operator) { @@ -1209,6 +1255,50 @@ pub fn query_all_validator_publickeys(conn: &Connection) -> DbResult Ok(public_keys) } +pub fn upsert_owner_fee_recipient(conn: &Connection, owner: Address, fee_recipient: Address) { + let owner = format!("{0:0x}", owner); + let fee_recipient = format!("{0:0x}", fee_recipient); + if let Err(e) = conn.execute("insert into owner_fee_recipient(owner, fee_recipient) values(?1, ?2) ON conflict(owner) do update set fee_recipient = (?3)", params![owner, fee_recipient, fee_recipient]) { + error!("Can't insert into owner fee recipient, error: {}", e); + } +} + +pub fn query_owner_fee_recipient(conn: &Connection, owner: Address) -> DbResult> { + let owner = format!("{0:0x}", owner); + match conn.prepare("select fee_recipient from owner_fee_recipient where owner = (?)") { + Ok(mut stmt) => { + let mut rows = stmt.query([owner])?; + while let Some(row) = rows.next()? { + let fee_recipient: String = row.get(0)?; + return Ok(Some(Address::from_slice(&hex::decode(&fee_recipient).unwrap()))); + } + return Ok(None); + } + Err(e) => { + error!("Can't prepare statement {}", e); + return Err(e); + } + } +} + +#[tokio::test] +async fn test_fee_recipient() { + let mut logger = + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")); + logger.format_timestamp_millis(); + logger.init(); + let _ = Database::new("/tmp/test.db").unwrap(); + let mut conn = Connection::open("/tmp/test.db").unwrap(); + let owner = Address::random(); + let fee_recipient = Address::random(); + let new_fee_recipient = Address::random(); + assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(None)); + upsert_owner_fee_recipient(&conn, owner, fee_recipient); + assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(Some(fee_recipient))); + upsert_owner_fee_recipient(&conn, owner, new_fee_recipient); + assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(Some(new_fee_recipient))); +} + #[tokio::test] async fn test_database() { use crate::crypto::ThresholdSignature; diff --git a/src/node/node.rs b/src/node/node.rs index bc5b9d2..95f7670 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -651,6 +651,8 @@ pub async fn add_validator( default_keystore_share_path(&keystore_share, validator_dir.clone()); let voting_keystore_share_password_path = default_keystore_share_password_path(&keystore_share, secret_dir.clone()); + + match &node.validator_store { Some(validator_store) => { let _ = validator_store diff --git a/src/validation/cli.rs b/src/validation/cli.rs index aa437ee..20b07d1 100644 --- a/src/validation/cli.rs +++ b/src/validation/cli.rs @@ -154,17 +154,17 @@ pub fn cli_app() -> Command { .display_order(0) .required(true) ) - // .arg( - // Arg::new("extra-contract") - // .long("extra-contract") - // .value_name("EXTRA_CONTRACT") - // .help( - // "This is the address of extra contract" - // ) - // .action(ArgAction::Set) - // .display_order(0) - // .required(true) - // ) + .arg( + Arg::new("config-contract") + .long("config-contract") + .value_name("CONFIG_CONTRACT") + .help( + "This is the address of config contract" + ) + .action(ArgAction::Set) + .display_order(0) + .required(true) + ) .arg( Arg::new("init-slashing-protection") .long("init-slashing-protection") diff --git a/src/validation/config.rs b/src/validation/config.rs index da5230f..a2d66d2 100644 --- a/src/validation/config.rs +++ b/src/validation/config.rs @@ -1,6 +1,6 @@ use crate::node::config::{NodeConfig, API_ADDRESS}; use crate::node::contract::{ - DEFAULT_TRANSPORT_URL, NETWORK_CONTRACT, REGISTRY_CONTRACT, SELF_OPERATOR_ID, + DEFAULT_TRANSPORT_URL, NETWORK_CONTRACT, REGISTRY_CONTRACT, SELF_OPERATOR_ID, CONFIG_CONTRACT }; use crate::validation::beacon_node_fallback::ApiTopic; use crate::validation::graffiti_file::GraffitiFile; @@ -163,9 +163,9 @@ impl Config { info!(log, "read network contract"; "network-contract" => &network_contract); NETWORK_CONTRACT.set(network_contract).unwrap(); - // let extra_contract: String = parse_required(cli_args, "extra-contract")?; - // info!(log, "read extra contract"; "extra-contract" => &extra_contract); - // EXTRA_CONTRACT.set(extra_contract).unwrap(); + let config_contract: String = parse_required(cli_args, "config-contract")?; + info!(log, "read config contract"; "config-contract" => &config_contract); + CONFIG_CONTRACT.set(config_contract).unwrap(); let self_ip: Ipv4Addr = parse_required(cli_args, "ip")?; info!(log, "read node ip"; "ip" => &self_ip.to_string()); From 0ed34c13401f3d1e2d988f0f63e084c0a82c40c0 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Mon, 28 Oct 2024 15:40:44 +0000 Subject: [PATCH 11/32] verify fee recipient address --- src/node/db.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++- src/node/dvfcore.rs | 30 ++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/node/db.rs b/src/node/db.rs index 6cb7ef3..b1899fa 100644 --- a/src/node/db.rs +++ b/src/node/db.rs @@ -42,7 +42,8 @@ pub enum DbCommand { QueryAllValidatorPublicKeys(oneshot::Sender>>), QueryValidatorRegistrationTimestamp(String, oneshot::Sender>), UpsertOwnerFeeRecipient(Address, Address), - QueryOwnerFeeRecipient(Address, oneshot::Sender>>) + QueryOwnerFeeRecipient(Address, oneshot::Sender>>), + CheckValidatorFeeRecipient(Vec, Address, oneshot::Sender>) } #[derive(Clone, Debug)] @@ -257,6 +258,10 @@ impl Database { let response = query_owner_fee_recipient(&mut conn, owner); let _ = sender.send(response); } + DbCommand::CheckValidatorFeeRecipient(pubkey, fee_recipient, sender) => { + let response = check_validator_fee_recipient(&mut conn, pubkey, fee_recipient); + let _ = sender.send(response); + } } } }); @@ -663,6 +668,23 @@ impl Database { .await .expect("Failed to receive reply of query fee recipient address from db") } + + pub async fn check_validator_fee_recipient( + &self, + pubkey: Vec, + fee_recipient: Address + ) -> DbResult { + let (sender, receiver) = oneshot::channel(); + if let Err(e) = self.channel.send(DbCommand::CheckValidatorFeeRecipient(pubkey, fee_recipient, sender)).await { + panic!( + "Failed to send check validator fee recipient address to store: {}", + e + ); + } + receiver + .await + .expect("Failed to receive reply of check validator fee recipient address from db") + } } fn insert_operator(conn: &Connection, operator: Operator) { @@ -1281,6 +1303,38 @@ pub fn query_owner_fee_recipient(conn: &Connection, owner: Address) -> DbResult< } } +pub fn check_validator_fee_recipient(conn: &Connection, pubkey: Vec, fee_recipient: Address) -> DbResult { + let pk = hex::encode(pubkey); + match conn.prepare("select owner_fee_recipient.fee_recipient from validators join owner_fee_recipient on validators.owner_address = owner_fee_recipient.owner where validators.public_key = (?)") { + Ok(mut stmt) => { + let mut rows = stmt.query([pk.clone()])?; + while let Some(row) = rows.next()? { + let res: String = row.get(0)?; + return Ok(res == format!("{0:0x}", fee_recipient)); + } + } + Err(e) => { + error!("Can't prepare statement {}", e); + return Err(e); + } + } + match conn.prepare("select owner_address from validators where public_key = (?)") { + Ok(mut stmt) => { + let mut rows = stmt.query([pk])?; + while let Some(row) = rows.next()? { + let res: String = row.get(0)?; + return Ok(res == format!("{0:0x}", fee_recipient)); + } + } + Err(e) => { + error!("Can't prepare statement {}", e); + return Err(e); + } + } + + Ok(false) +} + #[tokio::test] async fn test_fee_recipient() { let mut logger = @@ -1290,13 +1344,29 @@ async fn test_fee_recipient() { let _ = Database::new("/tmp/test.db").unwrap(); let mut conn = Connection::open("/tmp/test.db").unwrap(); let owner = Address::random(); + let mut rng = rand::thread_rng(); + let mut dest = [0u8; 48]; + rng.fill_bytes(&mut dest); + let pubkey = dest.to_vec(); + let validator = Validator { + id: 1, + owner_address: owner.clone(), + public_key: pubkey.clone(), + releated_operators: vec![], + active: true + }; + insert_validator(&mut conn, validator, 0); + assert_eq!(check_validator_fee_recipient(&conn, pubkey.clone(), owner).unwrap(), true); let fee_recipient = Address::random(); let new_fee_recipient = Address::random(); + assert_eq!(check_validator_fee_recipient(&conn, pubkey.clone(), fee_recipient).unwrap(), false); assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(None)); upsert_owner_fee_recipient(&conn, owner, fee_recipient); + assert_eq!(check_validator_fee_recipient(&conn, pubkey.clone(), fee_recipient).unwrap(), true); assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(Some(fee_recipient))); upsert_owner_fee_recipient(&conn, owner, new_fee_recipient); assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(Some(new_fee_recipient))); + assert_eq!(check_validator_fee_recipient(&conn, pubkey.clone(), new_fee_recipient).unwrap(), true); } #[tokio::test] diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index 303eaf0..8f61316 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -33,8 +33,10 @@ use store::Store; use tokio::sync::RwLock; use types::{ AbstractExecPayload, AttestationData, BeaconBlock, BlindedPayload, EthSpec, FullPayload, - Keypair, + Keypair, ExecPayload }; +use crate::node::db::Database; + #[derive(Serialize, Deserialize, Clone)] pub struct DvfInfo { pub validator_id: u64, @@ -147,6 +149,7 @@ pub struct DvfDutyCheckMessage { pub data: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub sign_hex: Option, + pub pubkey: Vec } impl DvfDutyCheckMessage { @@ -167,6 +170,7 @@ pub struct DvfDutyCheckHandler { pub validator_pk: BlsPublicKey, pub operator_pks: HashMap, pub keypair: Keypair, + pub db: Database, _phantom: PhantomData, } @@ -412,6 +416,17 @@ impl MessageHandler for DvfDutyCheckHandler { return Ok(()); } }; + let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); + if self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { + reply( + writer, + DutySafety::Invalid, + format!("fee recipient is not consistent"), + ) + .await; + error!("fee recipient is not consistent"); + return Ok(()); + } self.sign_block(writer, block, check_msg.domain_hash).await; } BlockType::Blinded => { @@ -429,6 +444,17 @@ impl MessageHandler for DvfDutyCheckHandler { return Ok(()); } }; + let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); + if self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { + reply( + writer, + DutySafety::Invalid, + format!("fee recipient is not consistent"), + ) + .await; + error!("fee recipient is not consistent"); + return Ok(()); + } self.sign_block(writer, block, check_msg.domain_hash).await; } }; @@ -522,6 +548,7 @@ impl DvfSigner { validator_pk: operator_committee.get_validator_pk(), operator_pks, keypair: keypair.clone(), + db: node.db.clone(), _phantom: PhantomData, }, ); @@ -590,6 +617,7 @@ impl DvfSigner { check_type, data: data.to_vec(), sign_hex: None, + pubkey: self.validator_public_key().serialize().to_vec() }; match msg.sign_digest(&self.node_secret) { Ok(sign_hex) => msg.sign_hex = Some(sign_hex), From 7c63ebec96e6f2291ff6b34c7747288efb9cf107 Mon Sep 17 00:00:00 2001 From: jiangjianlin Date: Tue, 29 Oct 2024 00:24:40 +0000 Subject: [PATCH 12/32] fix fee recipient --- src/node/db.rs | 1 + src/node/dvfcore.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/node/db.rs b/src/node/db.rs index b1899fa..6152e4c 100644 --- a/src/node/db.rs +++ b/src/node/db.rs @@ -1337,6 +1337,7 @@ pub fn check_validator_fee_recipient(conn: &Connection, pubkey: Vec, fee_rec #[tokio::test] async fn test_fee_recipient() { + use rand::RngCore; let mut logger = env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")); logger.format_timestamp_millis(); diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index 8f61316..f2b6676 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -417,7 +417,7 @@ impl MessageHandler for DvfDutyCheckHandler { } }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); - if self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { + if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { reply( writer, DutySafety::Invalid, @@ -445,7 +445,7 @@ impl MessageHandler for DvfDutyCheckHandler { } }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); - if self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { + if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { reply( writer, DutySafety::Invalid, From 72952f51313efa0cf9bbedcd194aa77580ec138d Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Tue, 29 Oct 2024 09:21:15 +0000 Subject: [PATCH 13/32] update event name --- src/node/contract.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/contract.rs b/src/node/contract.rs index b3e6b8b..559a9d7 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -33,7 +33,7 @@ const CONTRACT_INI_REG_EVENT_NAME: &str = "InitiatorRegistration"; const CONTRACT_MINIPOOL_CREATED_EVENT_NAME: &str = "InitiatorMiniPoolCreated"; const CONTRACT_MINIPOOL_READY_EVENT_NAME: &str = "InitiatorMiniPoolReady"; const CONTRACT_INI_RM_EVENT_NAME: &str = "InitiatorRemoval"; -const CONTRACT_FEE_RECIPIENT_SET_EVENT_NAME: &str = "FeeReceiptAddressSet"; +const CONTRACT_FEE_RECIPIENT_SET_EVENT_NAME: &str = "FeeRecipientAddressChanged"; pub static SELF_OPERATOR_ID: OnceCell = OnceCell::const_new(); pub static DEFAULT_TRANSPORT_URL: OnceCell = OnceCell::const_new(); pub static REGISTRY_CONTRACT: OnceCell = OnceCell::const_new(); @@ -319,7 +319,7 @@ impl TopicHandler for FeeRecipientSetHandler { _web3: &Web3, ) -> Result<(), ContractError> { process_fee_recipient_set(log, db).await.map_err(|e| { - error!("error happens when process initiator removal"); + error!("error happens when process set fee recipient"); e }) } From 565b8eec7486540452384bfeacf3c083e919ac33 Mon Sep 17 00:00:00 2001 From: mlbones666 <127071266+mlbones666@users.noreply.github.com> Date: Tue, 29 Oct 2024 20:27:02 +0800 Subject: [PATCH 14/32] add monitoring doc --- docs/safestake-running-an-operator-node.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/safestake-running-an-operator-node.md b/docs/safestake-running-an-operator-node.md index 932aaa8..4e3ab91 100644 --- a/docs/safestake-running-an-operator-node.md +++ b/docs/safestake-running-an-operator-node.md @@ -259,6 +259,10 @@ Some description of the folders and files under `/data/operator/v1/mainnet/`: ├── validators # data files of the validators that the operator is serving, inherited from the native folder of lighthouse validator client, including slashing_protection.sqlite, etc. ``` +## Monitoring + +You can use prometheus to fetch metrics from port `5064` of operator and monitor if the metric `vc_signed_attestations_total{status="success"}` is increasing to know if your operator is active. + ## Common issues troubleshooting ```mermaid graph TD; From ebd0f20f4ab623479d5b3040c97d47279c30f5ef Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Thu, 31 Oct 2024 15:38:17 +0000 Subject: [PATCH 15/32] fix parse log error --- src/node/contract.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/contract.rs b/src/node/contract.rs index 559a9d7..a621053 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -1176,12 +1176,12 @@ pub async fn process_fee_recipient_set(raw_log: Log, db: &Database) -> Result<() EventParam { name: "owner".to_string(), kind: ParamType::Address, - indexed: true, + indexed: false, }, EventParam { name: "newAddress".to_string(), kind: ParamType::Address, - indexed: true, + indexed: false, }, ], anonymous: false, From 8d3d37865260dae870bfd066cdfe86e91bbe00e6 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Sun, 3 Nov 2024 12:35:37 +0000 Subject: [PATCH 16/32] add debug log --- src/node/db.rs | 13 +++++++++++++ src/node/dvfcore.rs | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/node/db.rs b/src/node/db.rs index 6152e4c..0e80474 100644 --- a/src/node/db.rs +++ b/src/node/db.rs @@ -1335,6 +1335,19 @@ pub fn check_validator_fee_recipient(conn: &Connection, pubkey: Vec, fee_rec Ok(false) } +#[tokio::test] +async fn test_check_fee_recipient() { + let mut logger = + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")); + logger.format_timestamp_millis(); + logger.init(); + let _ = Database::new("/tmp/contract_database.db").unwrap(); + let conn = Connection::open("/tmp/contract_database.db").unwrap(); + let va_pk = hex::decode("82664f099bbd1a81ad878c2c2a3feb3c7caa3a623b5859018f6601da574e0ebd29432169610ed89b048f195f1fdcc024").unwrap(); + let address: Address = Address::from_slice(&hex::decode("331d29ac25cb8b7e52b5a7de0ba8e863682eca80").unwrap()); + assert_eq!(check_validator_fee_recipient(&conn, va_pk, address).unwrap(), true); +} + #[tokio::test] async fn test_fee_recipient() { use rand::RngCore; diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index f2b6676..a8ae9d8 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -417,6 +417,7 @@ impl MessageHandler for DvfDutyCheckHandler { } }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); + info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { reply( writer, @@ -445,6 +446,7 @@ impl MessageHandler for DvfDutyCheckHandler { } }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); + info!("block proposal blinded block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { reply( writer, From 1346a41e83bac79b1ee29d13d5423b885d58cda7 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Sun, 3 Nov 2024 12:55:22 +0000 Subject: [PATCH 17/32] fix change va owner --- src/node/contract.rs | 5 +++-- src/node/node.rs | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/node/contract.rs b/src/node/contract.rs index a621053..5a1f48b 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -139,6 +139,7 @@ pub enum ContractCommand { OperatorPublicKeys, SharedPublicKeys, EncryptedSecretKeys, + Address ), RemoveValidator(Validator), ActivateValidator(Validator), @@ -814,7 +815,7 @@ pub async fn process_validator_registration( //send command to node let validator = Validator { id: validator_id, - owner_address: fee_recipient_address, + owner_address: address, public_key: va_pk.try_into().unwrap(), releated_operators: op_ids, active: true, @@ -824,7 +825,7 @@ pub async fn process_validator_registration( // save validator in local database db.insert_validator(validator.clone(), registration_timestamp) .await; - let cmd = ContractCommand::StartValidator(validator, op_pk_bn, shared_pks, encrypted_sks); + let cmd = ContractCommand::StartValidator(validator, op_pk_bn, shared_pks, encrypted_sks, fee_recipient_address); db.insert_contract_command(validator_id, serde_json::to_string(&cmd).unwrap()) .await; } diff --git a/src/node/node.rs b/src/node/node.rs index 95f7670..06fadd4 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -50,7 +50,7 @@ use tokio::sync::RwLock; use tokio::time::{sleep, Duration}; use types::EthSpec; use validator_dir::insecure_keys::INSECURE_PASSWORD; -use web3::types::H160; +use web3::types::{H160, Address}; const THRESHOLD: u64 = 3; pub const COMMITTEE_IP_HEARTBEAT_INTERVAL: u64 = 1800; @@ -228,6 +228,7 @@ impl Node { operator_pks, shared_pks, encrypted_sks, + fee_recipient ) => { let va_id = validator.id; info!("StartValidator"); @@ -237,6 +238,7 @@ impl Node { operator_pks, shared_pks, encrypted_sks, + fee_recipient ) .await { @@ -530,6 +532,7 @@ pub async fn add_validator( operator_public_keys: OperatorPublicKeys, shared_public_keys: SharedPublicKeys, encrypted_secret_keys: EncryptedSecretKeys, + fee_recipient: Address ) -> Result<(), String> { let node = node.read().await; let validator_dir = node.config.validator_dir.clone(); @@ -661,7 +664,7 @@ pub async fn add_validator( voting_keystore_share_password_path, true, None, - Some(validator.owner_address), + Some(fee_recipient), None, Some(node.config.builder_proposals), node.config.builder_boost_factor, From 3b5f1334a8a568520dd0da7b9901c71966a569b1 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Mon, 4 Nov 2024 02:41:25 +0000 Subject: [PATCH 18/32] remove fee recipient check --- src/node/dvfcore.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index a8ae9d8..814ec02 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -447,16 +447,6 @@ impl MessageHandler for DvfDutyCheckHandler { }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); info!("block proposal blinded block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); - if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { - reply( - writer, - DutySafety::Invalid, - format!("fee recipient is not consistent"), - ) - .await; - error!("fee recipient is not consistent"); - return Ok(()); - } self.sign_block(writer, block, check_msg.domain_hash).await; } }; From c85caecef0d71d47e702644737208b0ff536a4be Mon Sep 17 00:00:00 2001 From: jianlinjiang <63327177+jianlinjiang@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:31:35 +0800 Subject: [PATCH 19/32] restart when fee recipient changed (#40) * update event name * fix parse log error * add debug log * fix change va owner * remove fee recipient check * restart when fee recipient changed --- src/node/contract.rs | 4 ++-- src/node/node.rs | 12 ++++++++++-- src/validation/validator_store.rs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/node/contract.rs b/src/node/contract.rs index 5a1f48b..049bfce 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -160,7 +160,7 @@ pub enum ContractCommand { Address, ), RemoveInitiator(Initiator, OperatorPublicKeys), - SetFeeRecipient(ValidatorPublicKey, Address), + SetFeeRecipient(u64, ValidatorPublicKey, Address), } #[derive(Clone)] @@ -1208,7 +1208,7 @@ pub async fn process_fee_recipient_set(raw_log: Log, db: &Database) -> Result<() // public key is zero for v in db.query_validator_by_address(owner).await.unwrap().iter() { - let cmd = ContractCommand::SetFeeRecipient(v.public_key.clone(), fee_recipient_address); + let cmd = ContractCommand::SetFeeRecipient(v.id, v.public_key.clone(), fee_recipient_address); db.insert_contract_command(v.id, serde_json::to_string(&cmd).unwrap()) .await; } diff --git a/src/node/node.rs b/src/node/node.rs index 06fadd4..0eb544b 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -389,9 +389,10 @@ impl Node { } } } - ContractCommand::SetFeeRecipient(va_pk, fee_recipient_address) => { + ContractCommand::SetFeeRecipient(va_id, va_pk, fee_recipient_address) => { match set_validator_fee_recipient( node.clone(), + va_id, va_pk, fee_recipient_address, ) @@ -1091,6 +1092,7 @@ pub async fn restart_validator( pub async fn set_validator_fee_recipient( node: Arc>>, + validator_id: u64, validator_pk: Vec, fee_recipient_address: H160, ) -> Result<(), DvfError> { @@ -1103,14 +1105,20 @@ pub async fn set_validator_fee_recipient( let node_ = node.read().await; node_.validator_store.clone() }; + cleanup_handler(node.clone(), validator_id).await; match validator_store { Some(validator_store) => { + let validator_pk = BlsPublicKey::deserialize(&validator_pk).unwrap(); validator_store .set_fee_recipient_for_validator( - &BlsPublicKey::deserialize(&validator_pk).unwrap(), + &validator_pk, fee_recipient_address, ) .await; + + validator_store + .restart_validator_keystore(&validator_pk) + .await; Ok(()) } _ => Err(DvfError::ValidatorStoreNotReady), diff --git a/src/validation/validator_store.rs b/src/validation/validator_store.rs index e306252..a26a755 100644 --- a/src/validation/validator_store.rs +++ b/src/validation/validator_store.rs @@ -1176,7 +1176,7 @@ impl ValidatorStore { "pubkey" => format!("{:?}", pubkey)); self.stop_validator_keystore(pubkey).await; // Cooling down - tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; + tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; self.start_validator_keystore(pubkey).await; } From 6538bcdfa5e5e0ec0d8a21027581e76b9db0bfad Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Wed, 6 Nov 2024 14:41:00 +0000 Subject: [PATCH 20/32] update va registrtion timestamp when fee recipient changed --- src/node/contract.rs | 10 ++++---- src/node/db.rs | 29 ++++++++++++++++++++++- src/validation/preparation_service.rs | 33 +-------------------------- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/node/contract.rs b/src/node/contract.rs index 049bfce..8eb920e 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -317,9 +317,9 @@ impl TopicHandler for FeeRecipientSetHandler { db: &Database, _operator_pk_base64: &String, _config: &ContractConfig, - _web3: &Web3, + web3: &Web3, ) -> Result<(), ContractError> { - process_fee_recipient_set(log, db).await.map_err(|e| { + process_fee_recipient_set(log, db, web3).await.map_err(|e| { error!("error happens when process set fee recipient"); e }) @@ -1169,7 +1169,7 @@ pub async fn process_minipool_ready(raw_log: Log, db: &Database) -> Result<(), C } } -pub async fn process_fee_recipient_set(raw_log: Log, db: &Database) -> Result<(), ContractError> { +pub async fn process_fee_recipient_set(raw_log: Log, db: &Database, web3: &Web3,) -> Result<(), ContractError> { info!("process_fee_recipient_set"); let fee_recipient_set_event = Event { name: CONTRACT_FEE_RECIPIENT_SET_EVENT_NAME.to_string(), @@ -1203,11 +1203,13 @@ pub async fn process_fee_recipient_set(raw_log: Log, db: &Database) -> Result<() .clone() .into_address() .ok_or(ContractError::LogParseError)?; - + let block_number = raw_log.block_number.unwrap(); + let registration_timestamp = query_block_number_timestamp(block_number, web3).await?; db.upsert_owner_fee_recipient(owner, fee_recipient_address).await; // public key is zero for v in db.query_validator_by_address(owner).await.unwrap().iter() { + db.update_validator_registration_timestamp(v.public_key.clone(), registration_timestamp).await; let cmd = ContractCommand::SetFeeRecipient(v.id, v.public_key.clone(), fee_recipient_address); db.insert_contract_command(v.id, serde_json::to_string(&cmd).unwrap()) .await; diff --git a/src/node/db.rs b/src/node/db.rs index 0e80474..06b4ad3 100644 --- a/src/node/db.rs +++ b/src/node/db.rs @@ -43,7 +43,8 @@ pub enum DbCommand { QueryValidatorRegistrationTimestamp(String, oneshot::Sender>), UpsertOwnerFeeRecipient(Address, Address), QueryOwnerFeeRecipient(Address, oneshot::Sender>>), - CheckValidatorFeeRecipient(Vec, Address, oneshot::Sender>) + CheckValidatorFeeRecipient(Vec, Address, oneshot::Sender>), + UpdateValidatorRegistrationTimestamp(Vec, u64) } #[derive(Clone, Debug)] @@ -262,6 +263,9 @@ impl Database { let response = check_validator_fee_recipient(&mut conn, pubkey, fee_recipient); let _ = sender.send(response); } + DbCommand::UpdateValidatorRegistrationTimestamp(pubkey, timestamp) => { + update_validator_registration_timestamp(&conn, pubkey, timestamp); + } } } }); @@ -685,6 +689,19 @@ impl Database { .await .expect("Failed to receive reply of check validator fee recipient address from db") } + + pub async fn update_validator_registration_timestamp( + &self, + pubkey: Vec, + timestamp: u64 + ) { + if let Err(e) = self.channel.send(DbCommand::UpdateValidatorRegistrationTimestamp(pubkey, timestamp)).await { + panic!( + "Failed to send update validator registration timestamp {}", + e + ); + } + } } fn insert_operator(conn: &Connection, operator: Operator) { @@ -1335,6 +1352,13 @@ pub fn check_validator_fee_recipient(conn: &Connection, pubkey: Vec, fee_rec Ok(false) } +fn update_validator_registration_timestamp(conn: &Connection, pubkey: Vec, timestamp: u64) { + let pk = hex::encode(pubkey); + if let Err(e) = conn.execute("UPDATE validators_registration_timestamp SET registration_timestamp = ?1 WHERE public_key = ?2", params![timestamp, pk]) { + error!("Can't insert into owner fee recipient, error: {}", e); + } +} + #[tokio::test] async fn test_check_fee_recipient() { let mut logger = @@ -1381,6 +1405,9 @@ async fn test_fee_recipient() { upsert_owner_fee_recipient(&conn, owner, new_fee_recipient); assert_eq!(query_owner_fee_recipient(&conn, owner), Ok(Some(new_fee_recipient))); assert_eq!(check_validator_fee_recipient(&conn, pubkey.clone(), new_fee_recipient).unwrap(), true); + update_validator_registration_timestamp(&conn, pubkey.clone(), 10); + let pk_str = hex::encode(pubkey.clone()); + assert_eq!(query_validator_registration_timestamp(&conn, &pk_str).unwrap(), 10); } #[tokio::test] diff --git a/src/validation/preparation_service.rs b/src/validation/preparation_service.rs index 89b01ad..9522e9a 100644 --- a/src/validation/preparation_service.rs +++ b/src/validation/preparation_service.rs @@ -26,7 +26,7 @@ const PROPOSER_PREPARATION_LOOKAHEAD_EPOCHS: u64 = 2; const EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION: u64 = 1; /// The number of validator registrations to include per request to the beacon node. -const VALIDATOR_REGISTRATION_BATCH_SIZE: usize = 500; +const VALIDATOR_REGISTRATION_BATCH_SIZE: usize = 50; /// Builds an `PreparationService`. pub struct PreparationServiceBuilder { @@ -385,37 +385,6 @@ impl PreparationService { // Check if any have changed or it's been `EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION`. if let Some(slot) = self.slot_clock.now() { - // let epoch = slot.epoch(E::slots_per_epoch()); - // let start_slot = epoch.start_slot(E::slots_per_epoch()); - // let registration_duration = self.slot_clock.start_of(start_slot); - // match registration_duration { - // Some(duration) => { - // let registartion_timestamp = duration.as_secs(); - // if slot % (E::slots_per_epoch() * EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION) - // == 0 - // { - // self.publish_validator_registration_data( - // registration_keys, - // registartion_timestamp, - // epoch, - // ) - // .await?; - // } else if !changed_keys.is_empty() { - // self.publish_validator_registration_data( - // changed_keys, - // registartion_timestamp, - // epoch, - // ) - // .await?; - // } - // } - // _ => { - // error!( - // log, - // "Unable to calculate the regitration timestamp"; - // ) - // } - // } let epoch = slot.epoch(E::slots_per_epoch()); if slot % (E::slots_per_epoch() * EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION) == 0 { self.publish_validator_registration_data(registration_keys, epoch) From e3cd9ff16fd70c6c2d170fbfac420f8b3052b886 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Thu, 7 Nov 2024 03:39:28 +0000 Subject: [PATCH 21/32] don't need restart when fee recipient changed --- src/node/node.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/node/node.rs b/src/node/node.rs index 0eb544b..c565b7a 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -1092,7 +1092,7 @@ pub async fn restart_validator( pub async fn set_validator_fee_recipient( node: Arc>>, - validator_id: u64, + _validator_id: u64, validator_pk: Vec, fee_recipient_address: H160, ) -> Result<(), DvfError> { @@ -1105,7 +1105,6 @@ pub async fn set_validator_fee_recipient( let node_ = node.read().await; node_.validator_store.clone() }; - cleanup_handler(node.clone(), validator_id).await; match validator_store { Some(validator_store) => { let validator_pk = BlsPublicKey::deserialize(&validator_pk).unwrap(); @@ -1115,10 +1114,6 @@ pub async fn set_validator_fee_recipient( fee_recipient_address, ) .await; - - validator_store - .restart_validator_keystore(&validator_pk) - .await; Ok(()) } _ => Err(DvfError::ValidatorStoreNotReady), From 622c175bed20ea689a3a47db37e423ea1b76c448 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Thu, 14 Nov 2024 14:41:20 +0000 Subject: [PATCH 22/32] bump version to 1.3.5 --- common/dvf_version/src/lib.rs | 6 ++++-- hotstuff/network/src/dvf_message.rs | 2 +- hotstuff/network/src/receiver.rs | 10 +++++----- src/node/dvfcore.rs | 20 ++++++++++---------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/common/dvf_version/src/lib.rs b/common/dvf_version/src/lib.rs index b03dab1..7622615 100644 --- a/common/dvf_version/src/lib.rs +++ b/common/dvf_version/src/lib.rs @@ -6,6 +6,8 @@ pub const ROOT_VERSION: u64 = 1; /// Up to 1 million pub const MAJOR_VERSION: u64 = 3; /// Up to 1 million -pub const MINOR_VERSION: u64 = 4; +pub const MINOR_VERSION: u64 = 5; -pub static VERSION: u64 = ROOT_VERSION * 1000_000_000_000 + MAJOR_VERSION * 1000_000 + MINOR_VERSION; \ No newline at end of file +pub static VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + MINOR_VERSION; + +pub static MIN_VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + 4; \ No newline at end of file diff --git a/hotstuff/network/src/dvf_message.rs b/hotstuff/network/src/dvf_message.rs index b6db944..4a44940 100644 --- a/hotstuff/network/src/dvf_message.rs +++ b/hotstuff/network/src/dvf_message.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Debug; -pub use dvf_version::{VERSION}; +pub use dvf_version::{VERSION, MIN_VERSION}; #[derive(Debug, Serialize, Deserialize)] pub struct DvfMessage { diff --git a/hotstuff/network/src/receiver.rs b/hotstuff/network/src/receiver.rs index 78f3a41..07e8e76 100644 --- a/hotstuff/network/src/receiver.rs +++ b/hotstuff/network/src/receiver.rs @@ -10,9 +10,9 @@ use std::net::SocketAddr; use tokio::net::{TcpListener, TcpStream}; use tokio_util::codec::{Framed, LengthDelimitedCodec}; use std::collections::HashMap; -use std::sync::{Arc}; -use tokio::sync::{RwLock}; -use crate::dvf_message::{DvfMessage, VERSION}; +use std::sync::Arc; +use tokio::sync::RwLock; +use crate::dvf_message::{DvfMessage, MIN_VERSION}; use futures::SinkExt; use tokio::time::{sleep, Duration}; @@ -87,9 +87,9 @@ impl Receiver { Ok(dvf_message) => { let validator_id = dvf_message.validator_id; let version = dvf_message.version; - if version != VERSION { + if version < MIN_VERSION { let _ = writer.send(Bytes::from("Version mismatch")).await; - error!("[VA {}] Version mismatch: got ({}), expected ({})", validator_id, version, VERSION); + error!("[VA {}] Version mismatch: got ({}), minmal version ({})", validator_id, version, MIN_VERSION); sleep(Duration::from_secs(INVALID_MESSAGE_DELAY)).await; // [zico] Should we kill the connection here? // If we kill it, then a reliable sender can resend the message because the ACK is not normal, but it may cause the diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index 814ec02..03b1337 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -418,16 +418,16 @@ impl MessageHandler for DvfDutyCheckHandler { }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); - if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { - reply( - writer, - DutySafety::Invalid, - format!("fee recipient is not consistent"), - ) - .await; - error!("fee recipient is not consistent"); - return Ok(()); - } + // if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { + // reply( + // writer, + // DutySafety::Invalid, + // format!("fee recipient is not consistent"), + // ) + // .await; + // error!("fee recipient is not consistent"); + // return Ok(()); + // } self.sign_block(writer, block, check_msg.domain_hash).await; } BlockType::Blinded => { From 7b15962dfbabb9363b7c30b58bec0bbf0442b1c0 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Fri, 15 Nov 2024 01:46:43 +0000 Subject: [PATCH 23/32] reserve check --- src/node/dvfcore.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index 03b1337..814ec02 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -418,16 +418,16 @@ impl MessageHandler for DvfDutyCheckHandler { }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); - // if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { - // reply( - // writer, - // DutySafety::Invalid, - // format!("fee recipient is not consistent"), - // ) - // .await; - // error!("fee recipient is not consistent"); - // return Ok(()); - // } + if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { + reply( + writer, + DutySafety::Invalid, + format!("fee recipient is not consistent"), + ) + .await; + error!("fee recipient is not consistent"); + return Ok(()); + } self.sign_block(writer, block, check_msg.domain_hash).await; } BlockType::Blinded => { From 23218169f89f64e145bd29123576be6cd3f402c6 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Fri, 15 Nov 2024 05:32:54 +0000 Subject: [PATCH 24/32] add software version --- common/dvf_version/src/lib.rs | 6 ++++-- hotstuff/network/src/dvf_message.rs | 2 +- hotstuff/network/src/receiver.rs | 6 +++--- src/node/status_report.rs | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/common/dvf_version/src/lib.rs b/common/dvf_version/src/lib.rs index 7622615..7b9df99 100644 --- a/common/dvf_version/src/lib.rs +++ b/common/dvf_version/src/lib.rs @@ -6,8 +6,10 @@ pub const ROOT_VERSION: u64 = 1; /// Up to 1 million pub const MAJOR_VERSION: u64 = 3; /// Up to 1 million -pub const MINOR_VERSION: u64 = 5; +pub const MINOR_VERSION: u64 = 4; pub static VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + MINOR_VERSION; -pub static MIN_VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + 4; \ No newline at end of file + +pub const SOFTWARE_MINOR_VERSION: u64 = 5; +pub static SOFTWARE_VERSION: u64 = ROOT_VERSION * 1_000_000_000_000 + MAJOR_VERSION * 1_000_000 + SOFTWARE_MINOR_VERSION; \ No newline at end of file diff --git a/hotstuff/network/src/dvf_message.rs b/hotstuff/network/src/dvf_message.rs index 4a44940..bc77866 100644 --- a/hotstuff/network/src/dvf_message.rs +++ b/hotstuff/network/src/dvf_message.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Debug; -pub use dvf_version::{VERSION, MIN_VERSION}; +pub use dvf_version::{VERSION, SOFTWARE_VERSION}; #[derive(Debug, Serialize, Deserialize)] pub struct DvfMessage { diff --git a/hotstuff/network/src/receiver.rs b/hotstuff/network/src/receiver.rs index 07e8e76..c9aeb80 100644 --- a/hotstuff/network/src/receiver.rs +++ b/hotstuff/network/src/receiver.rs @@ -12,7 +12,7 @@ use tokio_util::codec::{Framed, LengthDelimitedCodec}; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; -use crate::dvf_message::{DvfMessage, MIN_VERSION}; +use crate::dvf_message::{DvfMessage, VERSION}; use futures::SinkExt; use tokio::time::{sleep, Duration}; @@ -87,9 +87,9 @@ impl Receiver { Ok(dvf_message) => { let validator_id = dvf_message.validator_id; let version = dvf_message.version; - if version < MIN_VERSION { + if version != VERSION { let _ = writer.send(Bytes::from("Version mismatch")).await; - error!("[VA {}] Version mismatch: got ({}), minmal version ({})", validator_id, version, MIN_VERSION); + error!("[VA {}] Version mismatch: got ({}), expected version ({})", validator_id, version, VERSION); sleep(Duration::from_secs(INVALID_MESSAGE_DELAY)).await; // [zico] Should we kill the connection here? // If we kill it, then a reliable sender can resend the message because the ACK is not normal, but it may cause the diff --git a/src/node/status_report.rs b/src/node/status_report.rs index 7d1c0f6..4f5f0f6 100644 --- a/src/node/status_report.rs +++ b/src/node/status_report.rs @@ -50,7 +50,7 @@ impl StatusReport { &metrics::SIGNED_ATTESTATIONS_TOTAL, &[metrics::SUCCESS], ) as usize, - version: dvf_version::VERSION as usize, + version: dvf_version::SOFTWARE_VERSION as usize, connected_nodes: metrics::int_counter(&metrics::DVT_VC_CONNECTED_NODES) as usize, sign_hex: None, From e52bba7da801daebfc4d3d625e339a707311780b Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Fri, 15 Nov 2024 05:42:06 +0000 Subject: [PATCH 25/32] add some features to remove warnings --- Cargo.toml | 7 ++++++- hotstuff/network/src/dvf_message.rs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6233594..f9153ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -139,7 +139,12 @@ sysinfo = "0.26" default = ["hotstuff_committee"] fake_committee = [] hotstuff_committee = [] - +spec-minimal = [] +gnosis = [] +jemalloc = [] +# Compiles the BLS crypto code so that the binary is portable across machines. +portable = ["bls/supranational-portable"] +modern = ["bls/supranational-force-adx"] [dev-dependencies] tokio-test = "*" diff --git a/hotstuff/network/src/dvf_message.rs b/hotstuff/network/src/dvf_message.rs index bc77866..9ed5610 100644 --- a/hotstuff/network/src/dvf_message.rs +++ b/hotstuff/network/src/dvf_message.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Debug; -pub use dvf_version::{VERSION, SOFTWARE_VERSION}; +pub use dvf_version::VERSION; #[derive(Debug, Serialize, Deserialize)] pub struct DvfMessage { From 2d0acd6296341afab061fe27c2ba032e7351e5ca Mon Sep 17 00:00:00 2001 From: azaliasmee Date: Sun, 17 Nov 2024 23:31:31 +0800 Subject: [PATCH 26/32] change git runner to dynamic one-off job --- .github/workflows/ci_dev.yml | 92 ++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci_dev.yml b/.github/workflows/ci_dev.yml index bf6998f..f025474 100644 --- a/.github/workflows/ci_dev.yml +++ b/.github/workflows/ci_dev.yml @@ -1,33 +1,56 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# GitHub recommends pinning actions to a commit SHA. -# To get a newer version, you will need to update the SHA. -# You can also reference a tag or branch, but the action may change without warning. - -name: UnitTest & Publish Image - +name: do-the-job on: push: branches: - dev - jobs: - push_to_registry: - name: Push Docker image to Docker Hub - runs-on: self-hosted + start-runner: + name: Start self-hosted EC2 runner + runs-on: ubuntu-latest + outputs: + label: ${{ steps.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Start EC2 runner + id: start-ec2-runner + uses: machulav/ec2-github-runner@v2.3.7 + with: + mode: start + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + ec2-image-id: ami-0a2d071e715c3a808 + ec2-instance-type: c6a.4xlarge + subnet-id: subnet-9aa9c8e1 + security-group-id: sg-0c35d2e12fe165fbb + aws-resource-tags: > # optional, requires additional permissions + [ + {"Key": "Name", "Value": "ec2-github-runner"}, + {"Key": "GitHubRepository", "Value": "${{ github.repository }}"} + ] + do-the-job: + name: UnitTest & Build & Publish Image + needs: start-runner # required to start the main job when the runner is ready + runs-on: ${{ needs.start-runner.outputs.label }} # run the job on the newly created runner + steps: + - name: Hello World1 + run: | + echo 'Hello World!' + /root/.cargo/bin/cargo version + - name: Check out the repo uses: actions/checkout@v3 - - - name: Log in to Docker Hub + + - name: Login to Docker Hub uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 @@ -37,9 +60,10 @@ jobs: - name: Checkout submodules run: git submodule update --init --recursive - - name: Unit Test - run: sudo runuser -f ubuntu -c '/home/ubuntu/.cargo/bin/cargo test test_dkg_secure_net -- --show-output' - + - name: Unit Testing + run: | + /root/.cargo/bin/cargo test test_dkg_secure_net -- --show-output + - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: @@ -49,3 +73,29 @@ jobs: labels: ${{ steps.meta.outputs.labels }} build-args: | CPU_NUM=16 + + - name: Bye + run: echo 'Congratulations!' + + stop-runner: + name: Stop self-hosted EC2 runner + needs: + - start-runner # required to get output from the start-runner job + - do-the-job # required to wait when the main job is done + runs-on: ubuntu-latest + if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Stop EC2 runner + uses: machulav/ec2-github-runner@v2 + with: + mode: stop + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + label: ${{ needs.start-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-runner.outputs.ec2-instance-id }} + From 781bc697a1d843029d1d08c4dde21d1643c1029e Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Wed, 20 Nov 2024 05:14:34 +0000 Subject: [PATCH 27/32] use option to support mainnet --- src/node/dvfcore.rs | 32 ++++++++++++++++++-------------- src/node/node.rs | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index 814ec02..6a108cc 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -149,7 +149,7 @@ pub struct DvfDutyCheckMessage { pub data: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub sign_hex: Option, - pub pubkey: Vec + pub pubkey: Option> } impl DvfDutyCheckMessage { @@ -417,16 +417,22 @@ impl MessageHandler for DvfDutyCheckHandler { } }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); - info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); - if !self.db.check_validator_fee_recipient(check_msg.pubkey, fee_recipient).await.unwrap() { - reply( - writer, - DutySafety::Invalid, - format!("fee recipient is not consistent"), - ) - .await; - error!("fee recipient is not consistent"); - return Ok(()); + + match check_msg.pubkey { + Some(pubkey) => { + info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(&pubkey), format!("{0:0x}", fee_recipient)); + if !self.db.check_validator_fee_recipient(pubkey, fee_recipient).await.unwrap() { + reply( + writer, + DutySafety::Invalid, + format!("fee recipient is not consistent"), + ) + .await; + error!("fee recipient is not consistent"); + return Ok(()); + } + } + None => {} } self.sign_block(writer, block, check_msg.domain_hash).await; } @@ -445,8 +451,6 @@ impl MessageHandler for DvfDutyCheckHandler { return Ok(()); } }; - let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); - info!("block proposal blinded block, va pubic key {}, fee recipient {}", hex::encode(check_msg.pubkey.clone()), format!("{0:0x}", fee_recipient)); self.sign_block(writer, block, check_msg.domain_hash).await; } }; @@ -609,7 +613,7 @@ impl DvfSigner { check_type, data: data.to_vec(), sign_hex: None, - pubkey: self.validator_public_key().serialize().to_vec() + pubkey: Some(self.validator_public_key().serialize().to_vec()) }; match msg.sign_digest(&self.node_secret) { Ok(sign_hex) => msg.sign_hex = Some(sign_hex), diff --git a/src/node/node.rs b/src/node/node.rs index c565b7a..9c746e1 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -819,7 +819,7 @@ pub async fn start_initiator( secp256k1::SecretKey::from_slice(&secret.0).expect("Unable to load secret key"); let node_public_key = secp256k1::PublicKey::from_secret_key(&secp, &node_secret_key); if operator_addrs.iter().any(|x| x.is_none()) { - sleep(Duration::from_secs(10)).await; + sleep(Duration::from_secs(5)).await; return Err("StartInitiator: Insufficient operators discovered for DKG".to_string()); } let operator_addrs: Vec = operator_addrs.iter().map(|x| x.unwrap()).collect(); From bb8c4748db7844d238356f6760d53b939388e7ec Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Wed, 20 Nov 2024 09:38:48 +0000 Subject: [PATCH 28/32] fix mainnet --- src/node/dvfcore.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/node/dvfcore.rs b/src/node/dvfcore.rs index 6a108cc..b55fb4d 100644 --- a/src/node/dvfcore.rs +++ b/src/node/dvfcore.rs @@ -149,7 +149,6 @@ pub struct DvfDutyCheckMessage { pub data: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub sign_hex: Option, - pub pubkey: Option> } impl DvfDutyCheckMessage { @@ -417,23 +416,19 @@ impl MessageHandler for DvfDutyCheckHandler { } }; let fee_recipient = block.body().execution_payload().unwrap().fee_recipient(); - - match check_msg.pubkey { - Some(pubkey) => { - info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(&pubkey), format!("{0:0x}", fee_recipient)); - if !self.db.check_validator_fee_recipient(pubkey, fee_recipient).await.unwrap() { - reply( - writer, - DutySafety::Invalid, - format!("fee recipient is not consistent"), - ) - .await; - error!("fee recipient is not consistent"); - return Ok(()); - } - } - None => {} + let pubkey = self.validator_pk.serialize().to_vec(); + info!("block proposal full block, va pubic key {}, fee recipient {}", hex::encode(&pubkey), format!("{0:0x}", fee_recipient)); + if !self.db.check_validator_fee_recipient(pubkey, fee_recipient).await.unwrap() { + reply( + writer, + DutySafety::Invalid, + format!("fee recipient is not consistent"), + ) + .await; + error!("fee recipient is not consistent"); + return Ok(()); } + self.sign_block(writer, block, check_msg.domain_hash).await; } BlockType::Blinded => { @@ -612,8 +607,7 @@ impl DvfSigner { domain_hash, check_type, data: data.to_vec(), - sign_hex: None, - pubkey: Some(self.validator_public_key().serialize().to_vec()) + sign_hex: None }; match msg.sign_digest(&self.node_secret) { Ok(sign_hex) => msg.sign_hex = Some(sign_hex), From a1fc188229a19da8c3e0686bfab02566b1e01958 Mon Sep 17 00:00:00 2001 From: jianlinjiang Date: Thu, 21 Nov 2024 04:56:26 +0000 Subject: [PATCH 29/32] query own fee from contract --- contract_config/SafeStakeOperatorConfig.json | 263 +++++++++++++++++++ contract_config/configs.yml | 1 + src/node/contract.rs | 39 ++- 3 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 contract_config/SafeStakeOperatorConfig.json diff --git a/contract_config/SafeStakeOperatorConfig.json b/contract_config/SafeStakeOperatorConfig.json new file mode 100644 index 0000000..217e02c --- /dev/null +++ b/contract_config/SafeStakeOperatorConfig.json @@ -0,0 +1,263 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "SafeStakeOperatorConfig", + "sourceName": "contracts/SafeStakeOperatorConfig.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAddress", + "type": "address" + } + ], + "name": "FeeRecipientAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "inputs": [], + "name": "ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NODE_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SIGNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_storage", + "outputs": [ + { + "internalType": "contract ISafeStakeStorage", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "checkRole", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "generate_storage_key", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "getFeeRecipientAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "storageAddress", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "setFeeRecipientAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_storageAddress", + "type": "address" + } + ], + "name": "setStorageAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610a72806100206000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063c3fb90d61161008c578063d547741f11610066578063d547741f1461028e578063dbcdc2cc146102a1578063ef5d6bbb146102b4578063fb895733146102c757600080fd5b8063c3fb90d614610255578063c4d66de814610268578063c5b951901461027b57600080fd5b80636088089e116100c85780636088089e1461014757806375b238fc146101be57806391d14854146101e5578063a1ebf35d1461022e57600080fd5b80632f2ff15d146100ef57806354892f021461010457806359b910d614610134575b600080fd5b6101026100fd3660046109b9565b6102ee565b005b6101176101123660046109e9565b61037e565b6040516001600160a01b0390911681526020015b60405180910390f35b6101026101423660046109e9565b610455565b6101b06101553660046109e9565b6040516bffffffffffffffffffffffff19606083901b16602082015272466565526563697069656e744164647265737360681b6034820152600090604701604051602081830303815290604052805190602001209050919050565b60405190815260200161012b565b6101b07f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b76081565b61021e6101f33660046109b9565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604051901515815260200161012b565b6101b07f017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f7281565b600254610117906001600160a01b031681565b6101026102763660046109e9565b6104af565b610102610289366004610a06565b61054e565b61010261029c3660046109b9565b61058c565b6101026102af3660046109e9565b610614565b6101026102c23660046109b9565b610711565b6101b07f1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a6911181565b6103187f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760336101f3565b61034e5760405162461bcd60e51b8152602060048201526002602482015261583160f01b60448201526064015b60405180910390fd5b60009182526001602081815260408085206001600160a01b0390941685529290529120805460ff19169091179055565b6000806103e0836040516bffffffffffffffffffffffff19606083901b16602082015272466565526563697069656e744164647265737360681b6034820152600090604701604051602081830303815290604052805190602001209050919050565b6002546040516321f8a72160e01b8152600481018390529192506001600160a01b0316906321f8a72190602401602060405180830381865afa15801561042a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044e9190610a1f565b9392505050565b7f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b76061047f8161054e565b506002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60006104bb6001610771565b905080156104d3576000805461ff0019166101001790555b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055610503610887565b801561054a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b5050565b61055881336101f3565b6105895760405162461bcd60e51b8152602060048201526002602482015261058360f41b6044820152606401610345565b50565b6105b67f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760336101f3565b6105e75760405162461bcd60e51b81526020600482015260026024820152612c1960f11b6044820152606401610345565b60009182526001602090815260408084206001600160a01b0390931684529190529020805460ff19169055565b604080513360601b6bffffffffffffffffffffffff191660208083019190915272466565526563697069656e744164647265737360681b6034830152825160278184030181526047909201909252805191012060009060025460405163ca446dd960e01b8152600481018390526001600160a01b03858116602483015292935091169063ca446dd990604401600060405180830381600087803b1580156106ba57600080fd5b505af11580156106ce573d6000803e3d6000fd5b5050604080513381526001600160a01b03861660208201527f05d899f2c039ff7edfb413f1f4fe82889c2efaace7f08d7ac5aebad905b27ced9350019050610541565b8161071b8161054e565b6001600160a01b03821661072e57600080fd5b506000918252600160208181526040808520338652909152808420805460ff199081169091556001600160a01b0393909316845290922080549091169091179055565b60008054610100900460ff16156107ff578160ff1660011480156107945750303b155b6107f75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610345565b506000919050565b60005460ff80841691161061086d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610345565b506000805460ff191660ff92909216919091179055600190565b600054610100900460ff166109045760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610345565b3360009081527f331bba8513ee4dd5811afc38fa48458378fe9b930e1c5bd9a2e37d456ee8c897602090815260408083208054600160ff1991821681179092557f911c709b9be4f1ae2b9f62542e6578f826afdf6fa62cd1aac81cae683df0add2845282852080548216831790557f427c45ac74610ad1057fc3524fc3fecaa3416dd8aa9baf907541659f889ee436909352922080549091169091179055565b6001600160a01b038116811461058957600080fd5b600080604083850312156109cc57600080fd5b8235915060208301356109de816109a4565b809150509250929050565b6000602082840312156109fb57600080fd5b813561044e816109a4565b600060208284031215610a1857600080fd5b5035919050565b600060208284031215610a3157600080fd5b815161044e816109a456fea2646970667358221220df8a267b97a47fb672406d4352b538f48dbdc28002ce5d838ddfbd494e7469c464736f6c63430008130033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063c3fb90d61161008c578063d547741f11610066578063d547741f1461028e578063dbcdc2cc146102a1578063ef5d6bbb146102b4578063fb895733146102c757600080fd5b8063c3fb90d614610255578063c4d66de814610268578063c5b951901461027b57600080fd5b80636088089e116100c85780636088089e1461014757806375b238fc146101be57806391d14854146101e5578063a1ebf35d1461022e57600080fd5b80632f2ff15d146100ef57806354892f021461010457806359b910d614610134575b600080fd5b6101026100fd3660046109b9565b6102ee565b005b6101176101123660046109e9565b61037e565b6040516001600160a01b0390911681526020015b60405180910390f35b6101026101423660046109e9565b610455565b6101b06101553660046109e9565b6040516bffffffffffffffffffffffff19606083901b16602082015272466565526563697069656e744164647265737360681b6034820152600090604701604051602081830303815290604052805190602001209050919050565b60405190815260200161012b565b6101b07f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b76081565b61021e6101f33660046109b9565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604051901515815260200161012b565b6101b07f017e667f4b8c174291d1543c466717566e206df1bfd6f30271055ddafdb18f7281565b600254610117906001600160a01b031681565b6101026102763660046109e9565b6104af565b610102610289366004610a06565b61054e565b61010261029c3660046109b9565b61058c565b6101026102af3660046109e9565b610614565b6101026102c23660046109b9565b610711565b6101b07f1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a6911181565b6103187f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760336101f3565b61034e5760405162461bcd60e51b8152602060048201526002602482015261583160f01b60448201526064015b60405180910390fd5b60009182526001602081815260408085206001600160a01b0390941685529290529120805460ff19169091179055565b6000806103e0836040516bffffffffffffffffffffffff19606083901b16602082015272466565526563697069656e744164647265737360681b6034820152600090604701604051602081830303815290604052805190602001209050919050565b6002546040516321f8a72160e01b8152600481018390529192506001600160a01b0316906321f8a72190602401602060405180830381865afa15801561042a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044e9190610a1f565b9392505050565b7f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b76061047f8161054e565b506002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60006104bb6001610771565b905080156104d3576000805461ff0019166101001790555b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055610503610887565b801561054a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b5050565b61055881336101f3565b6105895760405162461bcd60e51b8152602060048201526002602482015261058360f41b6044820152606401610345565b50565b6105b67f03783fac2efed8fbc9ad443e592ee30e61d65f471140c10ca155e937b435b760336101f3565b6105e75760405162461bcd60e51b81526020600482015260026024820152612c1960f11b6044820152606401610345565b60009182526001602090815260408084206001600160a01b0390931684529190529020805460ff19169055565b604080513360601b6bffffffffffffffffffffffff191660208083019190915272466565526563697069656e744164647265737360681b6034830152825160278184030181526047909201909252805191012060009060025460405163ca446dd960e01b8152600481018390526001600160a01b03858116602483015292935091169063ca446dd990604401600060405180830381600087803b1580156106ba57600080fd5b505af11580156106ce573d6000803e3d6000fd5b5050604080513381526001600160a01b03861660208201527f05d899f2c039ff7edfb413f1f4fe82889c2efaace7f08d7ac5aebad905b27ced9350019050610541565b8161071b8161054e565b6001600160a01b03821661072e57600080fd5b506000918252600160208181526040808520338652909152808420805460ff199081169091556001600160a01b0393909316845290922080549091169091179055565b60008054610100900460ff16156107ff578160ff1660011480156107945750303b155b6107f75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610345565b506000919050565b60005460ff80841691161061086d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610345565b506000805460ff191660ff92909216919091179055600190565b600054610100900460ff166109045760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610345565b3360009081527f331bba8513ee4dd5811afc38fa48458378fe9b930e1c5bd9a2e37d456ee8c897602090815260408083208054600160ff1991821681179092557f911c709b9be4f1ae2b9f62542e6578f826afdf6fa62cd1aac81cae683df0add2845282852080548216831790557f427c45ac74610ad1057fc3524fc3fecaa3416dd8aa9baf907541659f889ee436909352922080549091169091179055565b6001600160a01b038116811461058957600080fd5b600080604083850312156109cc57600080fd5b8235915060208301356109de816109a4565b809150509250929050565b6000602082840312156109fb57600080fd5b813561044e816109a4565b600060208284031215610a1857600080fd5b5035919050565b600060208284031215610a3157600080fd5b815161044e816109a456fea2646970667358221220df8a267b97a47fb672406d4352b538f48dbdc28002ce5d838ddfbd494e7469c464736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contract_config/configs.yml b/contract_config/configs.yml index 2e22bdb..6f43f53 100644 --- a/contract_config/configs.yml +++ b/contract_config/configs.yml @@ -8,3 +8,4 @@ initiator_removal_topic: 34ecedfa430a18df6cda4bc2313d74d224c6742df8e6a98eca2fda9 fee_recipient_set_topic: 05d899f2c039ff7edfb413f1f4fe82889c2efaace7f08d7ac5aebad905b27ced safestake_network_abi_path: contract_config/SafeStakeNetwork.json safestake_registry_abi_path: contract_config/SafeStakeRegistry.json +safestake_config_abi_path: contract_config/SafeStakeOperatorConfig.json \ No newline at end of file diff --git a/src/node/contract.rs b/src/node/contract.rs index 8eb920e..ee9f018 100644 --- a/src/node/contract.rs +++ b/src/node/contract.rs @@ -337,6 +337,7 @@ pub struct ContractConfig { pub fee_recipient_set_topic: String, pub safestake_network_abi_path: String, pub safestake_registry_abi_path: String, + pub safestake_config_abi_path: String } impl FromFile for ContractConfig {} @@ -806,12 +807,7 @@ pub async fn process_validator_registration( .into_iter() .map(|s| base64::decode(s).unwrap()) .collect(); - let fee_recipient_address = match db.query_owner_fee_recipient(address.clone()).await.map_err(|_| { - ContractError::DatabaseError - })? { - Some(a) => a, - None => address - }; + let fee_recipient_address = query_owner_fee_recipient(config, address.clone(), web3).await?; //send command to node let validator = Validator { id: validator_id, @@ -1236,6 +1232,37 @@ pub async fn query_block_number_timestamp( } } +pub async fn query_owner_fee_recipient( + config: &ContractConfig, + owner: Address, + web3: &Web3 +) -> Result { + let raw_abi = std::fs::read_to_string(&config.safestake_config_abi_path) + .or_else(|e| { + error!( + "Can't read from {} {}", + &config.safestake_config_abi_path, e + ); + Err(ContractError::FileError) + }) + .unwrap(); + let raw_json: Value = serde_json::from_str(&raw_abi).unwrap(); + let abi = raw_json["abi"].to_string(); + let address = Address::from_slice(&hex::decode(CONFIG_CONTRACT.get().unwrap()).unwrap()); + let contract = EthContract::from_json(web3.eth(), address, abi.as_bytes()) + .or_else(|e| { + error!("Can't create contract from json {}", e); + Err(ContractError::ContractParseError) + }) + .unwrap(); + let fee_recipient: Address = contract.query("getFeeRecipientAddress", (owner,), None, Options::default(), None).await + .or_else(|e| { + error!("Can't query from contract {}", e); + Err(ContractError::QueryError) + })?; + Ok(fee_recipient) +} + pub async fn query_operator_from_contract( config: &ContractConfig, id: u32, From 1f3ac675f774c5e25004330f9e76e91a808d44d2 Mon Sep 17 00:00:00 2001 From: mlbones666 <127071266+mlbones666@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:09:36 +0800 Subject: [PATCH 30/32] update CONFIG_CONTRACT_ADDRESS --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index e63c5d0..7f20413 100644 --- a/.env.example +++ b/.env.example @@ -7,7 +7,7 @@ OPERATOR_NETWORK=mainnet IMAGE_TAG=v3.4.0-mainnet REGISTRY_CONTRACT_ADDRESS=1a1f82f0365571A0b06df0992FC4D1BCc5Fdc6aD NETWORK_CONTRACT_ADDRESS=829f3c089fE315FCB2BC9506B237BB56b7c3335B -CONFIG_CONTRACT_ADDRESS=1EFB8c90381695584CcB117388Bba897b71e0635 +CONFIG_CONTRACT_ADDRESS=07FA0F7f3C67e4cdE0FC23A072dcD712CF9a06C1 API_SERVER=https://api-node.safestake.xyz/api/op/ # different chain has different ttd TTD=10790000 From 638d3ef402390961f58adc1970c865bc315fc3bb Mon Sep 17 00:00:00 2001 From: mlbones666 <127071266+mlbones666@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:20:25 +0800 Subject: [PATCH 31/32] update version --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 7f20413..56cce06 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ BESU_NETWORK=mainnet ERIGON_NETWORK=mainnet LIGHTHOUSE_NETWORK=mainnet OPERATOR_NETWORK=mainnet -IMAGE_TAG=v3.4.0-mainnet +IMAGE_TAG=v3.5.0-mainnet REGISTRY_CONTRACT_ADDRESS=1a1f82f0365571A0b06df0992FC4D1BCc5Fdc6aD NETWORK_CONTRACT_ADDRESS=829f3c089fE315FCB2BC9506B237BB56b7c3335B CONFIG_CONTRACT_ADDRESS=07FA0F7f3C67e4cdE0FC23A072dcD712CF9a06C1 From 4345164116380c97d6fefe678641d30a81435178 Mon Sep 17 00:00:00 2001 From: azaliasmee Date: Mon, 25 Nov 2024 14:46:04 +0800 Subject: [PATCH 32/32] upgrade prod build pipeline --- .github/workflows/ci_main.yml | 90 +++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci_main.yml b/.github/workflows/ci_main.yml index badbbf8..d4a6fd7 100644 --- a/.github/workflows/ci_main.yml +++ b/.github/workflows/ci_main.yml @@ -1,33 +1,56 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# GitHub recommends pinning actions to a commit SHA. -# To get a newer version, you will need to update the SHA. -# You can also reference a tag or branch, but the action may change without warning. - -name: Publish Docker image - +name: do-the-job on: push: tags: - '**-mainnet' - jobs: - push_to_registry: - name: Push Docker image to Docker Hub - runs-on: self-hosted + start-runner: + name: Start self-hosted EC2 runner + runs-on: ubuntu-latest + outputs: + label: ${{ steps.start-ec2-runner.outputs.label }} + ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Start EC2 runner + id: start-ec2-runner + uses: machulav/ec2-github-runner@v2.3.7 + with: + mode: start + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + ec2-image-id: ami-0a2d071e715c3a808 + ec2-instance-type: c6a.4xlarge + subnet-id: subnet-9aa9c8e1 + security-group-id: sg-0c35d2e12fe165fbb + aws-resource-tags: > # optional, requires additional permissions + [ + {"Key": "Name", "Value": "ec2-github-runner"}, + {"Key": "GitHubRepository", "Value": "${{ github.repository }}"} + ] + do-the-job: + name: UnitTest & Build & Publish Image + needs: start-runner # required to start the main job when the runner is ready + runs-on: ${{ needs.start-runner.outputs.label }} # run the job on the newly created runner steps: + - name: Hello World1 + run: | + echo 'Hello World!' + /root/.cargo/bin/cargo version + - name: Check out the repo uses: actions/checkout@v3 - - - name: Log in to Docker Hub + + - name: Login to Docker Hub uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - + - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 @@ -36,10 +59,9 @@ jobs: flavor: | latest=false - - name: Checkout submodules run: git submodule update --init --recursive - + - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: @@ -48,4 +70,30 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | - CPU_NUM=16 \ No newline at end of file + CPU_NUM=16 + + - name: Bye + run: echo 'Congratulations!' + + stop-runner: + name: Stop self-hosted EC2 runner + needs: + - start-runner # required to get output from the start-runner job + - do-the-job # required to wait when the main job is done + runs-on: ubuntu-latest + if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + - name: Stop EC2 runner + uses: machulav/ec2-github-runner@v2 + with: + mode: stop + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + label: ${{ needs.start-runner.outputs.label }} + ec2-instance-id: ${{ needs.start-runner.outputs.ec2-instance-id }} +