Skip to content

Commit

Permalink
StateRoot + minors related to #1237 (#1444)
Browse files Browse the repository at this point in the history
* download strategy + minors

* StateRoot struct

* MerkleProof -> Vec<u8> (any proof)

* StateRoot -> &StateRoot in query

* put sync_state_nodes_multishard into expensive tests
  • Loading branch information
Kouprin committed Oct 17, 2019
1 parent 37a0eb8 commit ec83a3b
Show file tree
Hide file tree
Showing 24 changed files with 244 additions and 309 deletions.
32 changes: 9 additions & 23 deletions chain/chain/src/chain.rs
Expand Up @@ -183,10 +183,9 @@ impl Chain {
let mut store = ChainStore::new(store);

// Get runtime initial state and create genesis block out of it.
let (state_store_update, state_roots, state_num_parts) = runtime_adapter.genesis_state();
let (state_store_update, state_roots) = runtime_adapter.genesis_state();
let genesis = Block::genesis(
state_roots.clone(),
state_num_parts.clone(),
chain_genesis.time,
runtime_adapter.num_shards(),
chain_genesis.gas_limit,
Expand Down Expand Up @@ -242,20 +241,12 @@ impl Chain {
store_update.save_block_header(genesis.header.clone());
store_update.save_block(genesis.clone());

for (chunk_header, (state_root, state_num_parts)) in
genesis.chunks.iter().zip(state_roots.iter().zip(state_num_parts.iter()))
for (chunk_header, state_root) in genesis.chunks.iter().zip(state_roots.iter())
{
store_update.save_chunk_extra(
&genesis.hash(),
chunk_header.inner.shard_id,
ChunkExtra::new(
state_root,
*state_num_parts,
vec![],
0,
chain_genesis.gas_limit,
0,
),
ChunkExtra::new(state_root, vec![], 0, chain_genesis.gas_limit, 0),
);
}

Expand Down Expand Up @@ -947,18 +938,17 @@ impl Chain {
)
.into());
}
let state_root = sync_prev_block.chunks[shard_id as usize].inner.prev_state_root;
let state_num_parts = sync_prev_block.chunks[shard_id as usize].inner.prev_state_num_parts;
let state_root = sync_prev_block.chunks[shard_id as usize].inner.prev_state_root.clone();

if part_id >= state_num_parts {
if part_id >= state_root.num_parts {
return Err(ErrorKind::Other(
"get_state_response_part fail: part_id out of bound".to_string(),
)
.into());
}
let (state_part, proof) = self
.runtime_adapter
.obtain_state_part(shard_id, part_id, state_root, state_num_parts)
.obtain_state_part(shard_id, part_id, &state_root)
.map_err(|err| ErrorKind::Other(err.to_string()))?;

Ok(ShardStateSyncResponsePart { state_part, proof })
Expand Down Expand Up @@ -1141,8 +1131,7 @@ impl Chain {
) -> Result<(), Error> {
let shard_state_header = self.get_received_state_header(shard_id, sync_hash)?;
let ShardStateSyncResponseHeader { chunk, .. } = shard_state_header;
let state_root = chunk.header.inner.prev_state_root;
let _state_num_parts = chunk.header.inner.prev_state_num_parts;
let state_root = &chunk.header.inner.prev_state_root;
self.runtime_adapter
.accept_state_part(state_root, &part.state_part, &part.proof)
.map_err(|_| ErrorKind::InvalidStatePayload)?;
Expand All @@ -1163,13 +1152,12 @@ impl Chain {
incoming_receipts_proofs,
root_proofs: _,
} = shard_state_header;
let state_root = chunk.header.inner.prev_state_root;
let state_num_parts = chunk.header.inner.prev_state_num_parts;
let state_root = &chunk.header.inner.prev_state_root;

let block_header = self.get_header_by_height(chunk.header.height_included)?.clone();

// Applying chunk is started here.
self.runtime_adapter.confirm_state(state_root, state_num_parts)?;
self.runtime_adapter.confirm_state(&state_root)?;

// Getting actual incoming receipts.
let mut receipt_proof_response: Vec<ReceiptProofResponse> = vec![];
Expand Down Expand Up @@ -1207,7 +1195,6 @@ impl Chain {
chain_store_update.save_trie_changes(apply_result.trie_changes);
let chunk_extra = ChunkExtra::new(
&apply_result.new_root,
apply_result.new_num_parts,
apply_result.validator_proposals,
apply_result.total_gas_burnt,
gas_limit,
Expand Down Expand Up @@ -1765,7 +1752,6 @@ impl<'a> ChainUpdate<'a> {
shard_id,
ChunkExtra::new(
&apply_result.new_root,
apply_result.new_num_parts,
apply_result.validator_proposals,
apply_result.total_gas_burnt,
gas_limit,
Expand Down
88 changes: 40 additions & 48 deletions chain/chain/src/test_utils.rs
Expand Up @@ -20,7 +20,8 @@ use near_primitives::transaction::{
TransferAction,
};
use near_primitives::types::{
AccountId, Balance, BlockIndex, EpochId, Gas, Nonce, ShardId, StateRoot, ValidatorStake,
AccountId, Balance, BlockIndex, EpochId, Gas, MerkleHash, Nonce, ShardId, StateRoot,
ValidatorStake,
};
use near_primitives::views::QueryResponse;
use near_store::test_utils::create_test_store;
Expand Down Expand Up @@ -58,8 +59,7 @@ pub struct KeyValueRuntime {
num_shards: ShardId,

// A mapping state_root => {account id => amounts}, for transactions and receipts
state: RwLock<HashMap<StateRoot, KVState>>,
state_num_parts: RwLock<HashMap<StateRoot, u64>>,
state: RwLock<HashMap<MerkleHash, KVState>>,
state_parts: RwLock<HashMap<CryptoHash, StatePart>>,
state_proofs: RwLock<HashMap<CryptoHash, MerklePath>>,

Expand Down Expand Up @@ -111,15 +111,14 @@ impl KeyValueRuntime {

let mut state = HashMap::new();
state.insert(
StateRoot::default(),
MerkleHash::default(),
KVState {
amounts: initial_amounts,
receipt_nonces: HashSet::default(),
tx_nonces: HashSet::default(),
},
);
// TODO initializing for StateRoot::default()?
let state_num_parts = HashMap::new();
// TODO MOO initializing for StateRoot::default()?
let state_parts = HashMap::new();
let state_proofs = HashMap::new();
KeyValueRuntime {
Expand All @@ -142,7 +141,6 @@ impl KeyValueRuntime {
validator_groups,
num_shards,
state: RwLock::new(state),
state_num_parts: RwLock::new(state_num_parts),
state_parts: RwLock::new(state_parts),
state_proofs: RwLock::new(state_proofs),
hash_to_epoch: RwLock::new(HashMap::new()),
Expand All @@ -152,8 +150,8 @@ impl KeyValueRuntime {
}
}

pub fn get_root(&self) -> StateRoot {
self.root
pub fn get_root(&self) -> CryptoHash {
self.root.hash
}

fn get_prev_height(
Expand Down Expand Up @@ -245,11 +243,15 @@ impl KeyValueRuntime {
}

impl RuntimeAdapter for KeyValueRuntime {
fn genesis_state(&self) -> (StoreUpdate, Vec<StateRoot>, Vec<u64>) {
fn genesis_state(&self) -> (StoreUpdate, Vec<StateRoot>) {
(
self.store.store_update(),
((0..self.num_shards()).map(|_| StateRoot::default()).collect()),
vec![17; self.num_shards() as usize], // TODO MOO
((0..self.num_shards())
.map(|_| StateRoot {
hash: CryptoHash::default(),
num_parts: DEFAULT_STATE_NUM_PARTS, /* TODO MOO */
})
.collect()),
)
}

Expand Down Expand Up @@ -466,8 +468,7 @@ impl RuntimeAdapter for KeyValueRuntime {
assert!(!generate_storage_proof);
let mut tx_results = vec![];

//println!("HERE! {:?}", state_root); // TODO MOO
let mut state = self.state.read().unwrap().get(state_root).cloned().unwrap();
let mut state = self.state.read().unwrap().get(&state_root.hash).cloned().unwrap();

let mut balance_transfers = vec![];

Expand Down Expand Up @@ -611,31 +612,23 @@ impl RuntimeAdapter for KeyValueRuntime {
let part = StatePart { shard_id, part_id: i as u64, data: data[begin..end].to_vec() };
parts.push(part);
}
let (new_state_root, proofs) = merklize(&parts);

self.state.write().unwrap().insert(new_state_root, state);
/*println!( TODO MOO
"QQQ {:?} datalen={:?} {:?} {:?}",
shard_id,
data.len(),
new_state_root,
state_num_parts
);*/
self.state_num_parts.write().unwrap().insert(new_state_root, state_num_parts as u64);
let (state_hash, proofs) = merklize(&parts);
let new_state_root = StateRoot { hash: state_hash, num_parts: state_num_parts as u64 };

self.state.write().unwrap().insert(new_state_root.hash, state);
for i in 0..state_num_parts {
let key = hash(&StatePartKey(i as u64, new_state_root).try_to_vec().unwrap());
assert!(verify_path(new_state_root, &proofs[i], &parts[i]));
let key = hash(&StatePartKey(i as u64, new_state_root.clone()).try_to_vec().unwrap());
assert!(verify_path(new_state_root.hash, &proofs[i], &parts[i]));
self.state_parts.write().unwrap().insert(key, parts[i].clone());
self.state_proofs.write().unwrap().insert(key, proofs[i].clone());
}

Ok(ApplyTransactionResult {
trie_changes: WrappedTrieChanges::new(
self.trie.clone(),
TrieChanges::empty(*state_root),
TrieChanges::empty(state_root.hash),
),
new_root: new_state_root,
new_num_parts: state_num_parts as u64,
transaction_results: tx_results,
receipt_result: new_receipts,
validator_proposals: vec![],
Expand All @@ -647,7 +640,7 @@ impl RuntimeAdapter for KeyValueRuntime {

fn query(
&self,
state_root: StateRoot,
state_root: &StateRoot,
_height: BlockIndex,
_block_timestamp: u64,
_block_hash: &CryptoHash,
Expand All @@ -662,7 +655,7 @@ impl RuntimeAdapter for KeyValueRuntime {
.state
.read()
.unwrap()
.get(&state_root)
.get(&state_root.hash)
.map_or_else(|| 0, |state| *state.amounts.get(&account_id2).unwrap_or(&0)),
locked: 0,
code_hash: CryptoHash::default(),
Expand All @@ -677,41 +670,41 @@ impl RuntimeAdapter for KeyValueRuntime {
&self,
shard_id: ShardId,
part_id: u64,
state_root: StateRoot,
state_num_parts: u64,
) -> Result<(StatePart, MerklePath), Box<dyn std::error::Error>> {
if part_id >= state_num_parts {
state_root: &StateRoot,
) -> Result<(StatePart, Vec<u8>), Box<dyn std::error::Error>> {
if part_id >= state_root.num_parts {
return Err("Invalid part_id in obtain_state_part".to_string().into());
}
if shard_id >= self.num_shards() {
return Err("Invalid shard_id in obtain_state_part".to_string().into());
}
let key = hash(&StatePartKey(part_id, state_root).try_to_vec().unwrap());
let key = hash(&StatePartKey(part_id, state_root.clone()).try_to_vec().unwrap());
let part = self.state_parts.read().unwrap().get(&key).unwrap().clone();
let proof = self.state_proofs.read().unwrap().get(&key).unwrap().clone();
assert!(verify_path(state_root, &proof, &part));
Ok((part, proof))
assert!(verify_path(state_root.hash, &proof, &part));
Ok((part, proof.try_to_vec()?))
}

fn accept_state_part(
&self,
state_root: StateRoot,
state_root: &StateRoot,
part: &StatePart,
proof: &MerklePath,
proof: &Vec<u8>,
) -> Result<(), Box<dyn std::error::Error>> {
if !verify_path(state_root, proof, part) {
let merkle_proof = MerklePath::try_from_slice(&proof)?;
if !verify_path(state_root.hash, &merkle_proof, part) {
return Err("set_shard_state failed: invalid StatePart".into());
}
let key = hash(&StatePartKey(part.part_id, state_root).try_to_vec().unwrap());
let key = hash(&StatePartKey(part.part_id, state_root.clone()).try_to_vec().unwrap());
self.state_parts.write().unwrap().insert(key, part.clone());
self.state_proofs.write().unwrap().insert(key, proof.to_vec());
self.state_proofs.write().unwrap().insert(key, merkle_proof);
Ok(())
}

fn confirm_state(&self, state_root: StateRoot, state_num_parts: u64) -> Result<bool, Error> {
fn confirm_state(&self, state_root: &StateRoot) -> Result<bool, Error> {
let mut data = vec![];
for i in 0..state_num_parts as usize {
let key = hash(&StatePartKey(i as u64, state_root).try_to_vec().unwrap());
for i in 0..state_root.num_parts as usize {
let key = hash(&StatePartKey(i as u64, state_root.clone()).try_to_vec().unwrap());
match self.state_parts.read().unwrap().get(&key) {
Some(part) => {
data.push(part.data.clone());
Expand All @@ -725,8 +718,7 @@ impl RuntimeAdapter for KeyValueRuntime {
}
let data_flatten: Vec<u8> = data.iter().flatten().cloned().collect();
let state = KVState::try_from_slice(&data_flatten).unwrap();
// println!("HERE RE! {:?} {:?}", state_root, state); // TODO MOO
self.state.write().unwrap().insert(state_root, state);
self.state.write().unwrap().insert(state_root.hash, state);
Ok(true)
}

Expand Down
21 changes: 9 additions & 12 deletions chain/chain/src/types.rs
Expand Up @@ -102,7 +102,6 @@ pub enum ValidatorSignatureVerificationResult {
pub struct ApplyTransactionResult {
pub trie_changes: WrappedTrieChanges,
pub new_root: StateRoot,
pub new_num_parts: u64,
pub transaction_results: Vec<ExecutionOutcomeWithId>,
pub receipt_result: ReceiptResult,
pub validator_proposals: Vec<ValidatorStake>,
Expand All @@ -117,7 +116,7 @@ pub struct ApplyTransactionResult {
pub trait RuntimeAdapter: Send + Sync {
/// Initialize state to genesis state and returns StoreUpdate, state root and initial validators.
/// StoreUpdate can be discarded if the chain past the genesis.
fn genesis_state(&self) -> (StoreUpdate, Vec<StateRoot>, Vec<u64>);
fn genesis_state(&self) -> (StoreUpdate, Vec<StateRoot>);

/// Verify block producer validity and return weight of given block for fork choice rule.
fn compute_block_weight(
Expand Down Expand Up @@ -302,7 +301,7 @@ pub trait RuntimeAdapter: Send + Sync {
/// Query runtime with given `path` and `data`.
fn query(
&self,
state_root: StateRoot,
state_root: &StateRoot,
height: BlockIndex,
block_timestamp: u64,
block_hash: &CryptoHash,
Expand All @@ -315,9 +314,8 @@ pub trait RuntimeAdapter: Send + Sync {
&self,
shard_id: ShardId,
part_id: u64,
state_root: StateRoot,
state_num_parts: u64,
) -> Result<(StatePart, MerklePath), Box<dyn std::error::Error>>;
state_root: &StateRoot,
) -> Result<(StatePart, Vec<u8>), Box<dyn std::error::Error>>;

/// Set state part that expected to be given state root with provided data.
/// Returns error if:
Expand All @@ -326,14 +324,14 @@ pub trait RuntimeAdapter: Send + Sync {
/// 3. The resulting part doesn't match the expected one.
fn accept_state_part(
&self,
state_root: StateRoot,
state_root: &StateRoot,
part: &StatePart,
proof: &MerklePath,
proof: &Vec<u8>,
) -> Result<(), Box<dyn std::error::Error>>;

/// Should be executed after accepting all the parts.
/// Returns `true` if state is set successfully.
fn confirm_state(&self, state_root: StateRoot, num_parts: u64) -> Result<bool, Error>;
fn confirm_state(&self, state_root: &StateRoot) -> Result<bool, Error>;

/// Build receipts hashes.
fn build_receipts_hashes(&self, receipts: &Vec<Receipt>) -> Result<Vec<CryptoHash>, Error> {
Expand Down Expand Up @@ -456,7 +454,7 @@ pub struct ShardStateSyncResponseHeader {
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
pub struct ShardStateSyncResponsePart {
pub state_part: StatePart,
pub proof: MerklePath,
pub proof: Vec<u8>,
}

#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
Expand All @@ -479,8 +477,7 @@ mod tests {
fn test_block_produce() {
let num_shards = 32;
let genesis = Block::genesis(
vec![StateRoot::default()],
vec![9], /* TODO MOO */
vec![StateRoot { hash: CryptoHash::default(), num_parts: 9 /* TODO MOO */ }],
Utc::now(),
num_shards,
1_000_000,
Expand Down

0 comments on commit ec83a3b

Please sign in to comment.