Skip to content

Commit 5baa576

Browse files
Seulgi Kimmergify[bot]
authored andcommitted
Implement the ChangeParams transaction
1 parent 96b3bd0 commit 5baa576

File tree

9 files changed

+824
-14
lines changed

9 files changed

+824
-14
lines changed

core/src/consensus/stake/actions.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub enum Action {
3434
},
3535
ChangeParams {
3636
metadata_seq: u64,
37-
params: CommonParams,
37+
params: Box<CommonParams>,
3838
signatures: Vec<Signature>,
3939
},
4040
}
@@ -62,7 +62,7 @@ impl Encodable for Action {
6262
s.begin_list(3 + signatures.len())
6363
.append(&ACTION_TAG_CHANGE_PARAMS)
6464
.append(metadata_seq)
65-
.append(params);
65+
.append(&**params);
6666
for signature in signatures {
6767
s.append(signature);
6868
}
@@ -110,7 +110,7 @@ impl Decodable for Action {
110110
})
111111
}
112112
let metadata_seq = rlp.val_at(1)?;
113-
let params = rlp.val_at(2)?;
113+
let params = Box::new(rlp.val_at(2)?);
114114
let signatures = (3..item_count).map(|i| rlp.val_at(i)).collect::<Result<_, _>>()?;
115115
Ok(Action::ChangeParams {
116116
metadata_seq,
@@ -133,7 +133,7 @@ mod tests {
133133
fn decode_fail_if_change_params_have_no_signatures() {
134134
let action = Action::ChangeParams {
135135
metadata_seq: 3,
136-
params: CommonParams::default_for_test(),
136+
params: CommonParams::default_for_test().into(),
137137
signatures: vec![],
138138
};
139139
assert_eq!(
@@ -149,7 +149,7 @@ mod tests {
149149
fn rlp_of_change_params() {
150150
rlp_encode_and_decode_test!(Action::ChangeParams {
151151
metadata_seq: 3,
152-
params: CommonParams::default_for_test(),
152+
params: CommonParams::default_for_test().into(),
153153
signatures: vec![Signature::random(), Signature::random()],
154154
});
155155
}

core/src/consensus/stake/mod.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ use std::ops::Deref;
2323
use std::sync::Arc;
2424

2525
use ccrypto::Blake;
26-
use ckey::{recover, Address};
27-
use cstate::{ActionHandler, StateResult, TopLevelState};
26+
use ckey::{public_to_address, recover, Address, Signature};
27+
use cstate::{ActionHandler, StateResult, TopLevelState, TopState};
2828
use ctypes::errors::{RuntimeError, SyntaxError};
29+
use ctypes::util::unexpected::Mismatch;
2930
use ctypes::{CommonParams, Header};
3031
use primitives::H256;
3132
use rlp::{Decodable, UntrustedRlp};
@@ -114,8 +115,10 @@ impl ActionHandler for Stake {
114115
}
115116
}
116117
Action::ChangeParams {
117-
..
118-
} => unimplemented!(),
118+
metadata_seq,
119+
params,
120+
signatures,
121+
} => change_params(state, metadata_seq, *params, &signatures),
119122
}
120123
}
121124

@@ -215,6 +218,40 @@ pub fn get_stakes(state: &TopLevelState) -> StateResult<HashMap<Address, u64>> {
215218
Ok(result)
216219
}
217220

221+
fn change_params(
222+
state: &mut TopLevelState,
223+
metadata_seq: u64,
224+
params: CommonParams,
225+
signatures: &[Signature],
226+
) -> StateResult<()> {
227+
// Update state first because the signature validation is more expensive.
228+
state.update_params(metadata_seq, params)?;
229+
230+
let action = Action::ChangeParams {
231+
metadata_seq,
232+
params: params.into(),
233+
signatures: vec![],
234+
};
235+
let encoded_action = H256::blake(rlp::encode(&action));
236+
let stakes = get_stakes(state)?;
237+
let signed_stakes = signatures.iter().try_fold(0, |sum, signature| {
238+
let public = recover(signature, &encoded_action).unwrap_or_else(|err| {
239+
unreachable!("The transaction with an invalid signature cannot pass the verification: {}", err);
240+
});
241+
let address = public_to_address(&public);
242+
stakes.get(&address).map(|stake| sum + stake).ok_or_else(|| RuntimeError::SignatureOfInvalidAccount(address))
243+
})?;
244+
let total_stakes: u64 = stakes.values().sum();
245+
if total_stakes / 2 >= signed_stakes {
246+
return Err(RuntimeError::InsufficientStakes(Mismatch {
247+
expected: total_stakes,
248+
found: signed_stakes,
249+
})
250+
.into())
251+
}
252+
Ok(())
253+
}
254+
218255
#[cfg(test)]
219256
mod tests {
220257
use super::action_data::get_account_key;

spec/Staking.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ It also does not provide a voting feature.
359359
The vote initiator should collect the signatures through the off-chain.
360360

361361
This transaction increases the `seq` of `Metadata` and changes the `params` of `Metadata`.
362+
The changed parameters are applied from the next block that the changing transaction is included.
362363

363364
### Action
364365
`[ 0xFF, metadata_seq, new_parameters, ...signatures ]`

state/src/impls/top_level.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use ctypes::transaction::{
4646
Action, AssetOutPoint, AssetTransferInput, AssetWrapCCCOutput, ShardTransaction, Transaction,
4747
};
4848
use ctypes::util::unexpected::Mismatch;
49-
use ctypes::{BlockNumber, ShardId};
49+
use ctypes::{BlockNumber, CommonParams, ShardId};
5050
use cvm::ChainTimeInfo;
5151
use hashdb::AsHashDB;
5252
use kvdb::DBTransaction;
@@ -989,6 +989,21 @@ impl TopState for TopLevelState {
989989
fn remove_action_data(&mut self, key: &H256) {
990990
self.top_cache.remove_action_data(key)
991991
}
992+
993+
fn update_params(&mut self, metadata_seq: u64, params: CommonParams) -> StateResult<()> {
994+
let mut metadata = self.get_metadata_mut()?;
995+
if metadata.seq() != metadata_seq {
996+
return Err(RuntimeError::InvalidSeq(Mismatch {
997+
found: metadata_seq,
998+
expected: metadata.seq(),
999+
})
1000+
.into())
1001+
}
1002+
1003+
metadata.set_params(params);
1004+
metadata.increase_seq();
1005+
Ok(())
1006+
}
9921007
}
9931008

9941009
fn is_active_account(state: &TopStateView, address: &Address) -> TrieResult<bool> {

state/src/item/metadata.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616

17+
use ctypes::{CommonParams, ShardId};
1718
use primitives::H256;
1819
use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp};
1920

20-
use ctypes::{CommonParams, ShardId};
21-
2221
use crate::CacheableItem;
2322

2423
#[derive(Clone, Debug, Default, PartialEq)]
@@ -33,7 +32,7 @@ pub struct Metadata {
3332
number_of_initial_shards: ShardId,
3433
hashes: Vec<H256>,
3534
term: TermMetadata,
36-
seq: usize,
35+
seq: u64,
3736
params: Option<CommonParams>,
3837
}
3938

@@ -78,10 +77,22 @@ impl Metadata {
7877
})
7978
}
8079

80+
pub fn seq(&self) -> u64 {
81+
self.seq
82+
}
83+
84+
pub fn increase_seq(&mut self) {
85+
self.seq += 1;
86+
}
87+
8188
pub fn params(&self) -> Option<&CommonParams> {
8289
self.params.as_ref()
8390
}
8491

92+
pub fn set_params(&mut self, params: CommonParams) {
93+
self.params = Some(params);
94+
}
95+
8596
pub fn change_term(&mut self, last_term_finished_block_num: u64, current_term_id: u64) {
8697
assert!(self.term.last_term_finished_block_num < last_term_finished_block_num);
8798
assert!(self.term.current_term_id < current_term_id);

state/src/traits.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use ckey::{public_to_address, Address, Public, Signature};
1818
use cmerkle::Result as TrieResult;
1919
use ctypes::transaction::ShardTransaction;
20-
use ctypes::{BlockNumber, ShardId};
20+
use ctypes::{BlockNumber, CommonParams, ShardId};
2121
use cvm::ChainTimeInfo;
2222
use primitives::{Bytes, H160, H256};
2323

@@ -181,6 +181,8 @@ pub trait TopState {
181181

182182
fn update_action_data(&mut self, key: &H256, data: Bytes) -> StateResult<()>;
183183
fn remove_action_data(&mut self, key: &H256);
184+
185+
fn update_params(&mut self, metadata_seq: u64, params: CommonParams) -> StateResult<()>;
184186
}
185187

186188
pub trait StateWithCache {

0 commit comments

Comments
 (0)