diff --git a/src/components/contracts/baseapp/src/app.rs b/src/components/contracts/baseapp/src/app.rs index 3a66d8929..667c6bc4d 100644 --- a/src/components/contracts/baseapp/src/app.rs +++ b/src/components/contracts/baseapp/src/app.rs @@ -305,7 +305,9 @@ impl crate::BaseApp { let mut coinbase_mint_foud = false; let mut delegator = H256::zero(); - let claim_on_contract_address = + let claim_on_contract_address = if td_height + > CFG.checkpoint.evm_staking_inital_height + { match H160::from_str(SYSTEM_ADDR).c(d!()).and_then( |from| { get_claim_on_contract_address::( @@ -321,8 +323,10 @@ impl crate::BaseApp { resp.log = e.to_string(); return (resp, vec![]); } - }; - + } + } else { + Default::default() + }; for pair in evt.attributes.iter() { let key = String::from_utf8(pair.key.clone()) .unwrap_or_default(); @@ -349,12 +353,15 @@ impl crate::BaseApp { .unwrap_or_default(); if topic == deposit_asset_topic { deposit_asset_foud = true; - } else if topic.starts_with( - &coinbase_mint_event_topic - [0..coinbase_mint_event_topic.len() - 1], - ) { + } else if td_height + > CFG.checkpoint.evm_staking_inital_height + && topic.starts_with( + &coinbase_mint_event_topic[0 + ..coinbase_mint_event_topic.len() + - 1], + ) + { if let Some(start) = topic.find(", 0x") { - println!("start:{}", start); coinbase_mint_foud = true; delegator = match H256::from_str( &topic[start + 2..topic.len() - 1], @@ -389,7 +396,9 @@ impl crate::BaseApp { resp.log = e.to_string(); } } - } else if staking_contract_found + } else if td_height + > CFG.checkpoint.evm_staking_inital_height + && staking_contract_found && coinbase_mint_foud { let data = diff --git a/src/components/contracts/baseapp/src/staking.rs b/src/components/contracts/baseapp/src/staking.rs index 342b1250d..1fa43b97e 100644 --- a/src/components/contracts/baseapp/src/staking.rs +++ b/src/components/contracts/baseapp/src/staking.rs @@ -308,15 +308,34 @@ impl EVMStaking for BaseApp { Ok(()) } - fn claim( + fn replace_delegator( &self, - td_addr: &[u8], - delegator_pk: &XfrPublicKey, - amount: u64, + validator: &[u8], + staker: &XfrPublicKey, + new_staker_address: H160, ) -> Result<()> { + let validator = H160::from_slice(validator); + let staker_address = mapping_address(staker); + + if let Err(e) = self.modules.evm_module.replace_delegator( + &self.deliver_state, + validator, + staker_address, + new_staker_address, + ) { + self.deliver_state.state.write().discard_session(); + self.deliver_state.db.write().discard_session(); + tracing::error!(target: "evm staking", "replace_delegator error:{:?}", e); + return Err(e); + } + + self.deliver_state.state.write().commit_session(); + self.deliver_state.db.write().commit_session(); + Ok(()) + } + fn claim(&self, td_addr: &[u8], delegator_pk: &XfrPublicKey) -> Result<()> { let validator = H160::from_slice(td_addr); let delegator = mapping_address(delegator_pk); - let amount = U256::from(amount); let from = H160::from_str(SYSTEM_ADDR).c(d!())?; if let Err(e) = self.modules.evm_module.claim( &self.deliver_state, @@ -324,7 +343,6 @@ impl EVMStaking for BaseApp { validator, delegator, delegator_pk, - amount, ) { self.deliver_state.state.write().discard_session(); self.deliver_state.db.write().discard_session(); @@ -346,7 +364,7 @@ fn mapping_rate(rate: [u64; 2]) -> U256 { U256::from(rate[0].saturating_mul(deciamls) / rate[1]) } -fn mapping_address(pk: &XfrPublicKey) -> H160 { +pub fn mapping_address(pk: &XfrPublicKey) -> H160 { let result = Keccak256::digest(pk.as_bytes()); H160::from_slice(&result.as_slice()[..20]) } diff --git a/src/components/contracts/modules/evm/contracts/EVMStaking.abi.json b/src/components/contracts/modules/evm/contracts/EVMStaking.abi.json index 68c0fd42d..c0f0863ea 100644 --- a/src/components/contracts/modules/evm/contracts/EVMStaking.abi.json +++ b/src/components/contracts/modules/evm/contracts/EVMStaking.abi.json @@ -101,11 +101,6 @@ "name": "validator", "type": "address" }, - { - "internalType": "address", - "name": "delegator", - "type": "address" - }, { "internalType": "uint256", "name": "amount", @@ -127,7 +122,7 @@ ], "name": "delegate", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -432,6 +427,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "validators", + "type": "address[]" + }, + { + "internalType": "address", + "name": "newDelegator", + "type": "address" + } + ], + "name": "replaceDelegator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "rewardAddr", @@ -496,7 +509,7 @@ ], "name": "stake", "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "payable", "type": "function" }, { @@ -523,11 +536,6 @@ "internalType": "address", "name": "delegator", "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" } ], "name": "systemClaim", @@ -558,6 +566,29 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "validators", + "type": "address[]" + }, + { + "internalType": "address", + "name": "oldDelegator", + "type": "address" + }, + { + "internalType": "address", + "name": "newDelegator", + "type": "address" + } + ], + "name": "systemReplaceDelegator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -718,11 +749,6 @@ "name": "validator", "type": "address" }, - { - "internalType": "address", - "name": "staker", - "type": "address" - }, { "internalType": "string", "name": "memo", diff --git a/src/components/contracts/modules/evm/src/lib.rs b/src/components/contracts/modules/evm/src/lib.rs index 214407453..9893b8a84 100644 --- a/src/components/contracts/modules/evm/src/lib.rs +++ b/src/components/contracts/modules/evm/src/lib.rs @@ -838,15 +838,10 @@ impl App { validator: H160, delegator: H160, delegator_pk: &XfrPublicKey, - amount: U256, ) -> Result<()> { let function = self.contracts.staking.function("systemClaim").c(d!())?; let input = function - .encode_input(&[ - Token::Address(validator), - Token::Address(delegator), - Token::Uint(amount), - ]) + .encode_input(&[Token::Address(validator), Token::Address(delegator)]) .c(d!())?; let gas_limit = u64::MAX; @@ -977,6 +972,64 @@ impl App { Ok(()) } + pub fn replace_delegator( + &self, + ctx: &Context, + validator: H160, + staker: H160, + new_staker: H160, + ) -> Result<()> { + let func = self + .contracts + .staking + .function("systemReplaceDelegator") + .c(d!())?; + + let validator = Token::Array(vec![Token::Address(validator)]); + let staker = Token::Address(staker); + let new_staker = Token::Address(new_staker); + + let input = func + .encode_input(&[validator, staker, new_staker]) + .c(d!())?; + + let gas_limit = u64::MAX; + let value = U256::zero(); + let from = H160::from_str(SYSTEM_ADDR).c(d!())?; + + tracing::info!( + target: "evm staking", + "systemReplaceStaker from:{:?} gas_limit:{} value:{} contracts_address:{:?} input:{}", + from, + gas_limit, + value, + self.contracts.staking_address, + hex::encode(&input) + ); + + let (_, logs, used_gas) = ActionRunner::::execute_systemc_contract( + ctx, + input.clone(), + from, + gas_limit, + self.contracts.staking_address, + value, + )?; + + Self::store_transaction( + ctx, + U256::from(gas_limit), + from, + self.contracts.staking_address, + value, + input, + &logs, + used_gas, + )?; + + Ok(()) + } + #[allow(clippy::too_many_arguments)] fn store_transaction( ctx: &Context, diff --git a/src/components/contracts/modules/evm/src/runtime/runner.rs b/src/components/contracts/modules/evm/src/runtime/runner.rs index 7eb7e2bae..a91e6e06a 100644 --- a/src/components/contracts/modules/evm/src/runtime/runner.rs +++ b/src/components/contracts/modules/evm/src/runtime/runner.rs @@ -1,6 +1,7 @@ use super::stack::FindoraStackState; // use crate::precompile::PrecompileSet; use crate::{App, Config}; +use config::abci::global_cfg::CFG; use ethereum_types::{H160, H256, U256}; use evm::{ executor::stack::{StackExecutor, StackSubstateMetadata}, @@ -51,10 +52,12 @@ impl ActionRunner { gas_price >= C::FeeCalculator::min_gas_price(), "GasPriceTooLow" ); - ensure!( - gas_price <= C::FeeCalculator::max_gas_price(), - "GasPriceTooHigh" - ); + if ctx.header.height > CFG.checkpoint.max_gas_price_limit { + ensure!( + gas_price <= C::FeeCalculator::max_gas_price(), + "GasPriceTooHigh" + ); + } gas_price } None => Default::default(), diff --git a/src/components/finutils/src/bins/fn.rs b/src/components/finutils/src/bins/fn.rs index 2a4f96b44..40889dc9f 100644 --- a/src/components/finutils/src/bins/fn.rs +++ b/src/components/finutils/src/bins/fn.rs @@ -25,6 +25,10 @@ #![deny(warnings)] +use std::str::FromStr; + +use fp_types::H160; + use { clap::{crate_authors, load_yaml, App}, finutils::common::{self, evm::*}, @@ -416,30 +420,15 @@ fn run() -> Result<()> { let target = m .value_of("target") .c(d!()) - .and_then(wallet::public_key_from_base64)?; - // let new_td_addr_pk = if let Some(new_td_address_str) = m.value_of("td_address") { - // let new_td_address = hex::decode(new_td_address_str) - // .c(d!("`td_address` is invalid hex. "))?; - - // if new_td_address.len() != 20 { - // return Err(eg!("Invalid tendermint address.")); - // } - - // if let Some(new_td_pk) = m.value_of("td_pubkey") { - // let pk_bytes = - // base64::decode(new_td_pk).c(d!("`td_pubkey` is invalid base64."))?; - - // let _ = tendermint::PublicKey::from_raw_ed25519(&pk_bytes) - // .c(d!("Invalid tendermint public key."))?; - - // Some((new_td_address, pk_bytes)) - // } else { - // return Err(eg!("missing `td_pubkey`")); - // } - // } else { - // None - // }; - common::replace_staker(target, None)?; + .and_then(|val| H160::from_str(val).c(d!()))?; + let td_addr = match m.value_of("validator-td-addr") { + Some(v) => v, + None => { + println!("{}", m.usage()); + return Ok(()); + } + }; + common::replace_staker(target, td_addr)?; } else if let Some(m) = matches.subcommand_matches("dev") { #[cfg(not(target_arch = "wasm32"))] { diff --git a/src/components/finutils/src/bins/fn.yml b/src/components/finutils/src/bins/fn.yml index 2317c30c2..98a3a95b8 100644 --- a/src/components/finutils/src/bins/fn.yml +++ b/src/components/finutils/src/bins/fn.yml @@ -488,6 +488,12 @@ subcommands: - replace_staker: about: Replace the staker of the validator with target address args: + - validator-td-addr: + help: stake FRAs to a custom validator + short: A + long: validator-td-addr + takes_value: true + value_name: TendermintAddr - target: help: the public key of new staker, you must be the staker of the validator, you could use `fn setup` to configure your secret key and public key. short: t @@ -495,18 +501,6 @@ subcommands: takes_value: true value_name: TARGET PUBLIC KEY required: true - - td_address: - help: the tendermint address that you may want to replace. - long: td_address - takes_value: true - value_name: TENDERMINT ADDRESS - required: false - - td_pubkey: - help: the tendermint public key that you may want to replace. - long: td_pubkey - takes_value: true - value_name: TENDERMINT PUBKEY - required: false - dev: about: Manage development clusters on your localhost args: diff --git a/src/components/finutils/src/common/mod.rs b/src/components/finutils/src/common/mod.rs index 7dc61cf60..534364f6c 100644 --- a/src/components/finutils/src/common/mod.rs +++ b/src/components/finutils/src/common/mod.rs @@ -837,10 +837,8 @@ pub fn version() -> &'static str { } ///operation to replace the staker. -pub fn replace_staker( - target_pubkey: XfrPublicKey, - new_td_addr_pk: Option<(Vec, Vec)>, -) -> Result<()> { +pub fn replace_staker(target_addr: fp_types::H160, td_addr: &str) -> Result<()> { + let td_addr = hex::decode(td_addr).c(d!())?; let keypair = get_keypair()?; let mut builder = utils::new_tx_builder().c(d!())?; @@ -849,7 +847,7 @@ pub fn replace_staker( builder.add_operation(op); })?; - builder.add_operation_replace_staker(&keypair, target_pubkey, new_td_addr_pk)?; + builder.add_operation_replace_staker(&keypair, target_addr, td_addr)?; let mut tx = builder.take_transaction(); tx.sign_to_map(&keypair); diff --git a/src/components/finutils/src/txn_builder/mod.rs b/src/components/finutils/src/txn_builder/mod.rs index f5f979585..dc4e37c45 100644 --- a/src/components/finutils/src/txn_builder/mod.rs +++ b/src/components/finutils/src/txn_builder/mod.rs @@ -8,7 +8,7 @@ use { credentials::CredUserSecretKey, curve25519_dalek::scalar::Scalar, - fp_types::crypto::MultiSigner, + fp_types::{crypto::MultiSigner, H160}, globutils::SignatureOf, ledger::{ converter::ConvertAccount, @@ -623,13 +623,13 @@ impl TransactionBuilder { pub fn add_operation_replace_staker( &mut self, keypair: &XfrKeyPair, - new_public_key: XfrPublicKey, - new_td_addr: Option<(Vec, Vec)>, + new_staker_address: H160, + td_addr: Vec, ) -> Result<&mut Self> { let ops = ReplaceStakerOps::new( keypair, - new_public_key, - new_td_addr, + new_staker_address, + td_addr, self.txn.body.no_replay_token, ); self.add_operation(Operation::ReplaceStaker(ops)); diff --git a/src/ledger/src/staking/evm.rs b/src/ledger/src/staking/evm.rs index e1eeb46e2..1eeee35b9 100644 --- a/src/ledger/src/staking/evm.rs +++ b/src/ledger/src/staking/evm.rs @@ -1,6 +1,7 @@ //! For interact with BaseApp (EVM) use super::{Delegation, Validator}; +use fp_types::H160; use once_cell::sync::{Lazy, OnceCell}; use parking_lot::{Mutex, RwLock}; use ruc::Result; @@ -45,11 +46,13 @@ pub trait EVMStaking: Sync + Send + 'static { memo: String, rate: [u64; 2], ) -> Result<()>; - /// claim call - fn claim( + /// + fn replace_delegator( &self, - td_addr: &[u8], - delegator_pk: &XfrPublicKey, - amount: u64, + validator: &[u8], + staker: &XfrPublicKey, + new_staker_address: H160, ) -> Result<()>; + /// claim call + fn claim(&self, td_addr: &[u8], delegator_pk: &XfrPublicKey) -> Result<()>; } diff --git a/src/ledger/src/staking/ops/claim.rs b/src/ledger/src/staking/ops/claim.rs index 8b094f23c..bbdd9ce71 100644 --- a/src/ledger/src/staking/ops/claim.rs +++ b/src/ledger/src/staking/ops/claim.rs @@ -38,13 +38,12 @@ impl ClaimOps { let cur_height = staking.cur_height() as i64; if cur_height > CFG.checkpoint.evm_staking_inital_height { self.verify()?; - let am = self.body.amount.c(d!(eg!("Missing amount.")))?; let td_addr = self.td_addr.clone().c(d!(eg!("Missing validator addr.")))?; EVM_STAKING .get() .c(d!())? .write() - .claim(&td_addr, &self.pubkey, am)?; + .claim(&td_addr, &self.pubkey)?; Ok(()) } else { self.verify() diff --git a/src/ledger/src/staking/ops/replace_staker.rs b/src/ledger/src/staking/ops/replace_staker.rs index e4752fbe5..b88b3b44b 100644 --- a/src/ledger/src/staking/ops/replace_staker.rs +++ b/src/ledger/src/staking/ops/replace_staker.rs @@ -4,8 +4,12 @@ //! use { - crate::data_model::{NoReplayToken, Transaction}, - crate::staking::Staking, + crate::{ + data_model::{NoReplayToken, Transaction}, + staking::{evm::EVM_STAKING, Staking}, + }, + config::abci::global_cfg::CFG, + fp_types::H160, ruc::*, serde::{Deserialize, Serialize}, zei::xfr::sig::{XfrKeyPair, XfrPublicKey, XfrSignature}, @@ -23,18 +27,15 @@ impl ReplaceStakerOps { ///create a new replace operation. pub fn new( keypair: &XfrKeyPair, - new_public_key: XfrPublicKey, - new_tendermint_params: Option<(Vec, Vec)>, + new_staker_address: H160, + td_addr: Vec, nonce: NoReplayToken, ) -> Self { - let new_tendermint_params = new_tendermint_params.map(|p| TendermintParams { - address: p.0, - pubkey: p.1, - }); - let body = Data { - new_public_key, - new_tendermint_params, + new_public_key: XfrPublicKey::default(), + new_tendermint_params: None, + new_staker_address: Some(new_staker_address), + td_addr: Some(td_addr), nonce, }; @@ -70,14 +71,34 @@ impl ReplaceStakerOps { _tx: &Transaction, ) -> Result<()> { self.verify()?; - dbg!(staking_simulator.check_and_replace_staker( - &self.pubkey, - self.body.new_public_key, - self.body - .new_tendermint_params + let cur_height = staking_simulator.cur_height() as i64; + if cur_height > CFG.checkpoint.evm_staking_inital_height { + let validator = self + .body + .td_addr .clone() - .map(|p| (p.address, p.pubkey)), - )) + .ok_or(eg!("replace staker validator not found"))?; + + let new_staker_address = self + .body + .new_staker_address + .ok_or(eg!("replace staker new_staker_address not found"))?; + + EVM_STAKING.get().c(d!())?.write().replace_delegator( + &validator, + &self.pubkey, + new_staker_address, + ) + } else { + dbg!(staking_simulator.check_and_replace_staker( + &self.pubkey, + self.body.new_public_key, + self.body + .new_tendermint_params + .clone() + .map(|p| (p.address, p.pubkey)), + )) + } } #[inline(always)] @@ -104,6 +125,10 @@ impl ReplaceStakerOps { pub struct Data { pub new_public_key: XfrPublicKey, pub new_tendermint_params: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub new_staker_address: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub td_addr: Option>, nonce: NoReplayToken, }