Skip to content
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

Introduced chunk API #1524

Merged
merged 2 commits into from
Oct 23, 2019
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
39 changes: 29 additions & 10 deletions chain/chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use chrono::prelude::{DateTime, Utc};
use chrono::Duration;
use log::{debug, info};

use near_primitives::block::genesis_chunks;
use near_primitives::hash::{hash, CryptoHash};
use near_primitives::merkle::{merklize, verify_path};
use near_primitives::receipt::Receipt;
Expand Down Expand Up @@ -185,11 +186,15 @@ impl Chain {

// Get runtime initial state and create genesis block out of it.
let (state_store_update, state_roots) = runtime_adapter.genesis_state();
let genesis = Block::genesis(
let genesis_chunks = genesis_chunks(
state_roots.clone(),
chain_genesis.time,
runtime_adapter.num_shards(),
chain_genesis.gas_limit,
);
let genesis = Block::genesis(
genesis_chunks.iter().map(|chunk| chunk.header.clone()).collect(),
chain_genesis.time,
chain_genesis.gas_limit,
chain_genesis.gas_price,
chain_genesis.total_supply,
);
Expand Down Expand Up @@ -227,6 +232,9 @@ impl Chain {
}
Err(err) => match err.kind() {
ErrorKind::DBNotFoundErr(_) => {
for chunk in genesis_chunks {
store_update.save_chunk(&chunk.chunk_hash, chunk.clone());
}
runtime_adapter.add_validator_proposals(
CryptoHash::default(),
genesis.hash(),
Expand All @@ -247,7 +255,15 @@ impl Chain {
store_update.save_chunk_extra(
&genesis.hash(),
chunk_header.inner.shard_id,
ChunkExtra::new(state_root, vec![], 0, chain_genesis.gas_limit, 0, 0, 0),
ChunkExtra::new(
state_root,
vec![],
0,
chain_genesis.gas_limit,
0,
0,
0,
),
);
}

Expand Down Expand Up @@ -1652,11 +1668,14 @@ impl<'a> ChainUpdate<'a> {
self.chain_store_update.get_chunk_clone_from_header(&chunk_header)?;

let any_transaction_is_invalid = chunk.transactions.iter().any(|t| {
self.chain_store_update.get_chain_store().check_blocks_on_same_chain(
&block.header,
&t.transaction.block_hash,
self.transaction_validity_period,
).is_err()
self.chain_store_update
.get_chain_store()
.check_blocks_on_same_chain(
&block.header,
&t.transaction.block_hash,
self.transaction_validity_period,
)
.is_err()
});
if any_transaction_is_invalid {
debug!(target: "chain", "Invalid transactions in the chunk: {:?}", chunk.transactions);
Expand Down Expand Up @@ -1693,7 +1712,7 @@ impl<'a> ChainUpdate<'a> {
gas_limit,
apply_result.total_rent_paid,
apply_result.total_validator_reward,
apply_result.total_balance_burnt
apply_result.total_balance_burnt,
),
);
// Save resulting receipts.
Expand Down Expand Up @@ -2200,7 +2219,7 @@ impl<'a> ChainUpdate<'a> {
gas_limit,
apply_result.total_rent_paid,
apply_result.total_validator_reward,
apply_result.total_balance_burnt
apply_result.total_balance_burnt,
);
self.chain_store_update.save_chunk_extra(&block_header.hash, shard_id, chunk_extra);

Expand Down
9 changes: 7 additions & 2 deletions chain/chain/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,17 +483,22 @@ mod tests {
use chrono::Utc;

use near_crypto::{InMemorySigner, KeyType, Signature};
use near_primitives::block::genesis_chunks;

use super::*;

#[test]
fn test_block_produce() {
let num_shards = 32;
let genesis = Block::genesis(
let genesis_chunks = genesis_chunks(
vec![StateRoot { hash: CryptoHash::default(), num_parts: 9 /* TODO MOO */ }],
Utc::now(),
num_shards,
1_000_000,
);
let genesis = Block::genesis(
genesis_chunks.into_iter().map(|chunk| chunk.header).collect(),
Utc::now(),
1_000_000,
100,
1_000_000_000,
);
Expand Down
1 change: 1 addition & 0 deletions chain/client/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ impl Message for GetBlock {

/// Actor message requesting a chunk by chunk hash and block hash + shard id.
pub enum GetChunk {
BlockHeight(BlockIndex, ShardId),
BlockHash(CryptoHash, ShardId),
ChunkHash(ChunkHash),
}
Expand Down
7 changes: 7 additions & 0 deletions chain/client/src/view_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ impl Handler<GetChunk> for ViewClientActor {
.get_chunk(&block.chunks[shard_id as usize].chunk_hash())
.map(Clone::clone)
})
},
GetChunk::BlockHeight(block_height, shard_id) => {
self.chain.get_block_by_height(block_height).map(Clone::clone).and_then(|block| {
self.chain
.get_chunk(&block.chunks[shard_id as usize].chunk_hash())
.map(Clone::clone)
})
}
}
.map(|chunk| chunk.into())
Expand Down
12 changes: 10 additions & 2 deletions chain/jsonrpc/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use serde::Deserialize;
use serde::Serialize;

use near_primitives::hash::CryptoHash;
use near_primitives::types::BlockIndex;
use near_primitives::types::{BlockIndex, ShardId};
use near_primitives::views::{
BlockView, ExecutionOutcomeView, FinalExecutionOutcomeView, QueryResponse, StatusResponse,
BlockView, ChunkView, ExecutionOutcomeView, FinalExecutionOutcomeView, QueryResponse, StatusResponse,
};

use crate::message::{from_slice, Message};
Expand All @@ -22,6 +22,13 @@ pub enum BlockId {
Hash(CryptoHash),
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ChunkId {
BlockShardId(BlockId, ShardId),
Hash(CryptoHash),
}

/// Timeout for establishing connection.
const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);

Expand Down Expand Up @@ -180,6 +187,7 @@ jsonrpc_client!(pub struct JsonRpcClient {
pub fn tx(&mut self, hash: String) -> RpcRequest<FinalExecutionOutcomeView>;
pub fn tx_details(&mut self, hash: String) -> RpcRequest<ExecutionOutcomeView>;
pub fn block(&mut self, id: BlockId) -> RpcRequest<BlockView>;
pub fn chunk(&mut self, id: ChunkId) -> RpcRequest<ChunkView>;
});

/// Create new JSON RPC client that connects to the given address.
Expand Down
21 changes: 19 additions & 2 deletions chain/jsonrpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ use async_utils::{delay, timeout};
use message::Message;
use message::{Request, RpcError};
use near_client::{
ClientActor, GetBlock, GetNetworkInfo, Query, Status, TxDetails, TxStatus, ViewClientActor,
ClientActor, GetBlock, GetChunk, GetNetworkInfo, Query, Status, TxDetails, TxStatus, ViewClientActor,
};
pub use near_jsonrpc_client as client;
use near_jsonrpc_client::{message, BlockId};
use near_jsonrpc_client::{message, BlockId, ChunkId};
use near_metrics::{Encoder, TextEncoder};
use near_network::{NetworkClientMessages, NetworkClientResponses};
use near_primitives::hash::CryptoHash;
Expand Down Expand Up @@ -142,6 +142,7 @@ impl JsonRpcHandler {
"tx" => self.tx_status(request.params).await,
"tx_details" => self.tx_details(request.params).await,
"block" => self.block(request.params).await,
"chunk" => self.chunk(request.params).await,
"network_info" => self.network_info().await,
_ => Err(RpcError::method_not_found(request.method)),
}
Expand Down Expand Up @@ -238,6 +239,22 @@ impl JsonRpcHandler {
)
}

async fn chunk(&self, params: Option<Value>) -> Result<Value, RpcError> {
let (chunk_id,) = parse_params::<(ChunkId,)>(params)?;
jsonify(
self.view_client_addr
.send(match chunk_id {
ChunkId::BlockShardId(block_id, shard_id) => match block_id {
BlockId::Height(block_height) => GetChunk::BlockHeight(block_height, shard_id),
BlockId::Hash(block_hash) => GetChunk::BlockHash(block_hash.into(), shard_id),
},
ChunkId::Hash(chunk_hash) => GetChunk::ChunkHash(chunk_hash.into()),
})
.compat()
.await,
)
}

async fn network_info(&self) -> Result<Value, RpcError> {
jsonify(self.client_addr.send(GetNetworkInfo {}).compat().await)
}
Expand Down
53 changes: 52 additions & 1 deletion chain/jsonrpc/tests/rpc_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use actix::System;
use futures::future;
use futures::future::Future;

use near_crypto::Signature;
use near_jsonrpc::client::new_client;
use near_jsonrpc::test_utils::start_all;
use near_jsonrpc_client::BlockId;
use near_jsonrpc_client::{BlockId, ChunkId};
use near_primitives::hash::CryptoHash;
use near_primitives::test_utils::init_test_logger;
use near_primitives::types::ShardId;

/// Retrieve blocks via json rpc
#[test]
Expand Down Expand Up @@ -65,6 +67,55 @@ fn test_block_by_hash() {
.unwrap();
}

/// Retrieve blocks via json rpc
#[test]
fn test_chunk_by_hash() {
init_test_logger();

System::run(|| {
let (_view_client_addr, addr) = start_all(true);

let mut client = new_client(&format!("http://{}", addr.clone()));
actix::spawn(
client.chunk(ChunkId::BlockShardId(BlockId::Height(0), ShardId::from(0u64))).then(
move |chunk| {
let chunk = chunk.unwrap();
assert_eq!(chunk.header.balance_burnt, 0);
assert_eq!(chunk.header.chunk_hash.as_ref().len(), 32);
assert_eq!(chunk.header.encoded_length, 8);
assert_eq!(chunk.header.encoded_merkle_root.as_ref().len(), 32);
assert_eq!(chunk.header.gas_limit, 1000000);
assert_eq!(chunk.header.gas_used, 0);
assert_eq!(chunk.header.height_created, 0);
assert_eq!(chunk.header.height_included, 0);
assert_eq!(chunk.header.outgoing_receipts_root.as_ref().len(), 32);
assert_eq!(chunk.header.prev_block_hash.as_ref().len(), 32);
assert_eq!(chunk.header.prev_state_num_parts, 17);
assert_eq!(chunk.header.prev_state_root_hash.as_ref().len(), 32);
assert_eq!(chunk.header.rent_paid, 0);
assert_eq!(chunk.header.shard_id, 0);
assert!(if let Signature::ED25519(_) = chunk.header.signature {
true
} else {
false
});
assert_eq!(chunk.header.tx_root.as_ref(), &[0; 32]);
assert_eq!(chunk.header.validator_proposals, vec![]);
assert_eq!(chunk.header.validator_reward, 0);
let mut client = new_client(&format!("http://{}", addr));
client.chunk(ChunkId::Hash(chunk.header.chunk_hash)).then(move |same_chunk| {
let same_chunk = same_chunk.unwrap();
assert_eq!(chunk.header.chunk_hash, same_chunk.header.chunk_hash);
System::current().stop();
future::ok(())
})
},
),
);
})
.unwrap();
}

/// Connect to json rpc and query the client.
#[test]
fn test_query() {
Expand Down
10 changes: 7 additions & 3 deletions core/primitives/benches/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use chrono::Utc;

use near_crypto::{InMemorySigner, KeyType, PublicKey, Signature};
use near_primitives::account::Account;
use near_primitives::block::Block;
use near_primitives::block::{genesis_chunks, Block};
use near_primitives::hash::CryptoHash;
use near_primitives::transaction::{Action, SignedTransaction, Transaction, TransferAction};
use near_primitives::types::{EpochId, StateRoot};
Expand All @@ -33,11 +33,15 @@ fn create_transaction() -> SignedTransaction {
}

fn create_block() -> Block {
let genesis = Block::genesis(
let genesis_chunks = genesis_chunks(
vec![StateRoot { hash: CryptoHash::default(), num_parts: 1 /* TODO MOO */ }],
Utc::now(),
1,
1_000,
);
let genesis = Block::genesis(
genesis_chunks.into_iter().map(|chunk| chunk.header).collect(),
Utc::now(),
1_000,
1_000,
1_000,
);
Expand Down
60 changes: 35 additions & 25 deletions core/primitives/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use near_crypto::{EmptySigner, KeyType, PublicKey, Signature, Signer};

use crate::hash::{hash, CryptoHash};
use crate::merkle::merklize;
use crate::sharding::{ChunkHashHeight, ShardChunkHeader};
use crate::sharding::{ChunkHashHeight, EncodedShardChunk, ShardChunk, ShardChunkHeader};
use crate::types::{
Balance, BlockIndex, EpochId, Gas, MerkleHash, ShardId, StateRoot, ValidatorStake,
};
Expand Down Expand Up @@ -242,38 +242,48 @@ pub struct Block {
pub chunks: Vec<ShardChunkHeader>,
}

pub fn genesis_chunks(
state_roots: Vec<StateRoot>,
num_shards: ShardId,
initial_gas_limit: Gas,
) -> Vec<ShardChunk> {
assert!(state_roots.len() == 1 || state_roots.len() == (num_shards as usize));
(0..num_shards)
.map(|i| {
let (encoded_chunk, _) = EncodedShardChunk::new(
CryptoHash::default(),
state_roots[i as usize % state_roots.len()].clone(),
0,
i,
3,
1,
0,
initial_gas_limit,
0,
0,
0,
CryptoHash::default(),
vec![],
&vec![],
&vec![],
CryptoHash::default(),
&EmptySigner {},
)
.expect("Failed to decode genesis chunk");
encoded_chunk.decode_chunk(1).expect("Failed to decode genesis chunk")
})
.collect()
}

impl Block {
/// Returns genesis block for given genesis date and state root.
pub fn genesis(
state_roots: Vec<StateRoot>,
chunks: Vec<ShardChunkHeader>,
timestamp: DateTime<Utc>,
num_shards: ShardId,
initial_gas_limit: Gas,
initial_gas_price: Balance,
initial_total_supply: Balance,
) -> Self {
assert!(state_roots.len() == 1 || state_roots.len() == (num_shards as usize));
let chunks = (0..num_shards)
.map(|i| {
ShardChunkHeader::new(
CryptoHash::default(),
state_roots[i as usize % state_roots.len()].clone(),
CryptoHash::default(),
0,
0,
i,
0,
initial_gas_limit,
0,
0,
0,
CryptoHash::default(),
CryptoHash::default(),
vec![],
&EmptySigner {},
)
})
.collect();
Block {
header: BlockHeader::genesis(
Block::compute_state_root(&chunks),
Expand Down
Loading