Skip to content

Add a new field 'next validator set hash' in the header #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use super::invoice::Invoice;
use crate::client::{EngineInfo, TermInfo};
use crate::consensus::CodeChainEngine;
use crate::error::{BlockError, Error};
use crate::stake;
use crate::transaction::{SignedTransaction, UnverifiedTransaction};
use crate::BlockId;
use ccrypto::BLAKE_NULL_RLP;
Expand Down Expand Up @@ -232,6 +233,16 @@ impl<'x> OpenBlock<'x> {
e
})?;
self.block.header.set_state_root(state_root);

/*
FIXME: NextValidators entry doesn't exist in the state during static-validator-set-mode.
It doesn't cause a direct error since we use unwrap_or_default() here, but should be aware of such problem.
Remove this comment after we completely omit static-validator-set-mode.
*/
let vset_raw = stake::NextValidators::load_from_state(self.block.state())?;
let vset = vset_raw.create_compact_validator_set();
self.block.header.set_next_validator_set_hash(vset.hash());

Ok(())
}

Expand Down
7 changes: 6 additions & 1 deletion core/src/consensus/stake/action_data.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand All @@ -18,6 +18,7 @@ use super::CUSTOM_ACTION_HANDLER_ID;
use ckey::{public_to_address, Address, Public};
use cstate::{ActionData, ActionDataKeyBuilder, StateResult, TopLevelState, TopState, TopStateView};
use ctypes::errors::RuntimeError;
use ctypes::CompactValidatorSet;
use primitives::{Bytes, H256};
use rlp::{decode_list, encode_list, Decodable, Encodable, Rlp, RlpStream};
use std::cmp::Ordering;
Expand Down Expand Up @@ -287,6 +288,10 @@ impl NextValidators {
Ok(Self(validators))
}

pub fn create_compact_validator_set(&self) -> CompactValidatorSet {
CompactValidatorSet(self.0.iter().map(|x| (*x.pubkey(), x.delegation())).collect())
}

pub fn elect(state: &TopLevelState) -> StateResult<Self> {
let (delegation_threshold, max_num_of_validators, min_num_of_validators, min_deposit) = {
let metadata = state.metadata()?.expect("Metadata must exist");
Expand Down
7 changes: 6 additions & 1 deletion core/src/encoded.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -94,6 +94,11 @@ impl Header {
self.view().transactions_root()
}

/// Returns the transaction trie root.
pub fn next_validator_set_hash(&self) -> H256 {
self.view().next_validator_set_hash()
}

/// Score of this block
pub fn score(&self) -> U256 {
self.view().score()
Expand Down
3 changes: 3 additions & 0 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ pub enum BlockError {
InvalidStateRoot(Mismatch<H256>),
/// Transactions root header field is invalid.
InvalidTransactionsRoot(Mismatch<H256>),
/// Next validator set hash header field is invalid.
InvalidNextValidatorSetHash(Mismatch<H256>),
/// Score is out of range; this can be used as an looser error prior to getting a definitive
/// value for score. This error needs only provide bounds of which it is out.
ScoreOutOfBounds(OutOfBounds<U256>),
Expand Down Expand Up @@ -139,6 +141,7 @@ impl fmt::Display for BlockError {
InvalidSealArity(mis) => format!("Block seal in incorrect format: {}", mis),
InvalidStateRoot(mis) => format!("Invalid state root in header: {}", mis),
InvalidTransactionsRoot(mis) => format!("Invalid transactions root in header: {}", mis),
InvalidNextValidatorSetHash(mis) => format!("Invalid next validator set hash in header: {}", mis),
ScoreOutOfBounds(oob) => format!("Invalid block score: {}", oob),
InvalidScore(oob) => format!("Invalid block score: {}", oob),
InvalidProofOfWork => "Invalid proof of work.".into(),
Expand Down
3 changes: 3 additions & 0 deletions core/src/scheme/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub struct Genesis {
pub transactions_root: H256,
/// State root.
pub state_root: Option<H256>,
/// Next validator set hash.
pub next_validator_set_hash: Option<H256>,
/// The genesis block's extra data field.
pub extra_data: Bytes,
}
Expand All @@ -51,6 +53,7 @@ impl From<cjson::scheme::Genesis> for Genesis {
parent_hash: g.parent_hash.map_or_else(H256::zero, Into::into).into(),
transactions_root: g.transactions_root.map_or_else(|| BLAKE_NULL_RLP, Into::into),
state_root: g.state_root.map(Into::into),
next_validator_set_hash: g.next_validator_set_hash.map(Into::into),
extra_data: g.extra_data.map_or_else(Vec::new, Into::into),
}
}
Expand Down
1 change: 1 addition & 0 deletions core/src/scheme/scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ impl Scheme {
header.set_transactions_root(self.transactions_root);
header.set_extra_data(blake256(&self.genesis_params().rlp_bytes()).to_vec());
header.set_state_root(self.state_root());
header.set_next_validator_set_hash(BLAKE_NULL_RLP /* This will be calculated from state after https://github.com/CodeChain-io/foundry/issues/142*/);
header.set_score(self.score);
header.set_seal({
let r = Rlp::new(&self.seal_rlp);
Expand Down
6 changes: 6 additions & 0 deletions core/src/verification/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,11 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>
found: *got.state_root(),
})))
}
if expected.next_validator_set_hash() != got.next_validator_set_hash() {
return Err(From::from(BlockError::InvalidNextValidatorSetHash(Mismatch {
expected: *expected.next_validator_set_hash(),
found: *got.next_validator_set_hash(),
})))
}
Ok(())
}
17 changes: 11 additions & 6 deletions core/src/views/header.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -70,29 +70,34 @@ impl<'a> HeaderView<'a> {
self.rlp.val_at(3).unwrap()
}

/// Returns next validator set hash
pub fn next_validator_set_hash(&self) -> H256 {
self.rlp.val_at(4).unwrap()
}

/// Returns block score.
pub fn score(&self) -> U256 {
self.rlp.val_at(4).unwrap()
self.rlp.val_at(5).unwrap()
}

/// Returns block number.
pub fn number(&self) -> BlockNumber {
self.rlp.val_at(5).unwrap()
self.rlp.val_at(6).unwrap()
}

/// Returns timestamp.
pub fn timestamp(&self) -> u64 {
self.rlp.val_at(6).unwrap()
self.rlp.val_at(7).unwrap()
}

/// Returns block extra data.
pub fn extra_data(&self) -> Bytes {
self.rlp.val_at(7).unwrap()
self.rlp.val_at(8).unwrap()
}

/// Returns a vector of post-RLP-encoded seal fields.
pub fn seal(&self) -> Vec<Bytes> {
const SIZE_WITHOUT_SEAL: usize = 8;
const SIZE_WITHOUT_SEAL: usize = 9;

let item_count = self.rlp.item_count().unwrap();
let mut seal = Vec::with_capacity(item_count - SIZE_WITHOUT_SEAL);
Expand Down
8 changes: 6 additions & 2 deletions json/src/scheme/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -38,6 +38,8 @@ pub struct Genesis {
pub transactions_root: Option<H256>,
/// State root.
pub state_root: Option<H256>,
/// Next validator set hash.
pub next_validator_set_hash: Option<H256>,
/// Extra data.
pub extra_data: Option<Bytes>,
}
Expand Down Expand Up @@ -73,7 +75,8 @@ mod tests {
"timestamp": "0x07",
"parentHash": "0x9000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544",
"nextValidatorSetHash": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
}"#;
let deserialized: Genesis = serde_json::from_str(s).unwrap();
assert_eq!(deserialized, Genesis {
Expand All @@ -90,6 +93,7 @@ mod tests {
parent_hash: Some(H256(Core256::from("0x9000000000000000000000000000000000000000000000000000000000000000"))),
transactions_root: None,
state_root: Some(H256(Core256::from("0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"))),
next_validator_set_hash: Some(H256(Core256::from("0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"))),
extra_data: Some(Bytes::from_str("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa").unwrap()),
});
}
Expand Down
4 changes: 3 additions & 1 deletion rpc/src/v1/types/block.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -32,6 +32,7 @@ pub struct Block {

transactions_root: H256,
state_root: H256,
next_validator_set_hash: H256,

score: U256,
seal: Vec<Vec<u8>>,
Expand Down Expand Up @@ -62,6 +63,7 @@ impl Block {

transactions_root: *block.header.transactions_root(),
state_root: *block.header.state_root(),
next_validator_set_hash: *block.header.next_validator_set_hash(),

score: *block.header.score(),
seal: block.header.seal().to_vec(),
Expand Down
4 changes: 2 additions & 2 deletions test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
"blakejs": "^1.1.0",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"codechain-sdk": "^2.0.0-alpha.2",
"codechain-stakeholder-sdk": "https://github.com/majecty/codechain-stakeholder-sdk-js#v2.0.0-alpha.1",
"codechain-sdk": "https://github.com/junha1/codechain-sdk-js#test2.0.1",
"codechain-stakeholder-sdk": "https://github.com/junha1/codechain-stakeholder-sdk-js#master",
"elliptic": "^6.4.1",
"lodash": "^4.17.11",
"mkdirp": "^0.5.1",
Expand Down
11 changes: 10 additions & 1 deletion test/src/e2e.long/invalidBlockPropagation.helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -56,6 +56,7 @@ async function setup(): Promise<[Header, Block, Header]> {
Buffer.from(block0.extraData),
block0.transactionsRoot,
block0.stateRoot,
block0.nextValidatorSetHash,
block0.score,
block0.seal
);
Expand All @@ -67,6 +68,7 @@ async function setup(): Promise<[Header, Block, Header]> {
Buffer.from(block1.extraData),
block1.transactionsRoot,
block1.stateRoot,
block1.nextValidatorSetHash,
new U256(2222222222222),
block1.seal
);
Expand All @@ -78,6 +80,7 @@ async function setup(): Promise<[Header, Block, Header]> {
Buffer.from(block2.extraData),
block2.transactionsRoot,
block2.stateRoot,
block2.nextValidatorSetHash,
new U256(33333333333333),
block2.seal
);
Expand Down Expand Up @@ -113,6 +116,7 @@ async function testBody(
textraData?: Buffer;
ttransactionRoot?: H256;
tstateRoot?: H256;
tnextValidatorSetHash?: H256;
tscore?: U256;
tseal?: number[][];
}
Expand All @@ -125,6 +129,7 @@ async function testBody(
tauthor,
ttransactionRoot,
tstateRoot,
tnextValidatorSetHash,
tseal
} = params;

Expand All @@ -139,6 +144,7 @@ async function testBody(
Buffer.from(block1.extraData),
block1.transactionsRoot,
block1.stateRoot,
block1.nextValidatorSetHash,
new U256(2222222222222),
block1.seal
);
Expand All @@ -161,6 +167,9 @@ async function testBody(
if (tstateRoot != null) {
header.setStateRoot(tstateRoot);
}
if (tnextValidatorSetHash != null) {
header.setNextValidatorSetHash(tnextValidatorSetHash);
}
if (tscore != null) {
header.setScore(tscore);
}
Expand Down
5 changes: 4 additions & 1 deletion test/src/e2e.long/onChainBlockValid.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2019 Kodebox, Inc.
// Copyright 2018-2020 Kodebox, Inc.
// This file is part of CodeChain.
//
// This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -72,6 +72,7 @@ describe("Test onChain block communication", async function() {
Buffer.from(genesisBlock.extraData),
genesisBlock.transactionsRoot,
genesisBlock.stateRoot,
genesisBlock.nextValidatorSetHash,
genesisBlock.score,
genesisBlock.seal
);
Expand All @@ -83,6 +84,7 @@ describe("Test onChain block communication", async function() {
Buffer.from(block1.extraData),
block1.transactionsRoot,
block1.stateRoot,
block1.nextValidatorSetHash,
new U256(2222222222222),
block1.seal
);
Expand All @@ -94,6 +96,7 @@ describe("Test onChain block communication", async function() {
Buffer.from(block2.extraData),
block2.transactionsRoot,
block2.stateRoot,
block2.nextValidatorSetHash,
new U256(33333333333333),
block2.seal
);
Expand Down
Loading