Skip to content

Commit 0117e6a

Browse files
frolilblackdragon
authored andcommitted
Introduced chunk API (#1524)
* Introduced `chunk` API * Saving genesis chunks to make consistent output from chunks RPC
1 parent 75ff270 commit 0117e6a

File tree

12 files changed

+190
-55
lines changed

12 files changed

+190
-55
lines changed

chain/chain/src/chain.rs

+29-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use chrono::prelude::{DateTime, Utc};
77
use chrono::Duration;
88
use log::{debug, info};
99

10+
use near_primitives::block::genesis_chunks;
1011
use near_primitives::hash::{hash, CryptoHash};
1112
use near_primitives::merkle::{merklize, verify_path};
1213
use near_primitives::receipt::Receipt;
@@ -185,11 +186,15 @@ impl Chain {
185186

186187
// Get runtime initial state and create genesis block out of it.
187188
let (state_store_update, state_roots) = runtime_adapter.genesis_state();
188-
let genesis = Block::genesis(
189+
let genesis_chunks = genesis_chunks(
189190
state_roots.clone(),
190-
chain_genesis.time,
191191
runtime_adapter.num_shards(),
192192
chain_genesis.gas_limit,
193+
);
194+
let genesis = Block::genesis(
195+
genesis_chunks.iter().map(|chunk| chunk.header.clone()).collect(),
196+
chain_genesis.time,
197+
chain_genesis.gas_limit,
193198
chain_genesis.gas_price,
194199
chain_genesis.total_supply,
195200
);
@@ -227,6 +232,9 @@ impl Chain {
227232
}
228233
Err(err) => match err.kind() {
229234
ErrorKind::DBNotFoundErr(_) => {
235+
for chunk in genesis_chunks {
236+
store_update.save_chunk(&chunk.chunk_hash, chunk.clone());
237+
}
230238
runtime_adapter.add_validator_proposals(
231239
CryptoHash::default(),
232240
genesis.hash(),
@@ -247,7 +255,15 @@ impl Chain {
247255
store_update.save_chunk_extra(
248256
&genesis.hash(),
249257
chunk_header.inner.shard_id,
250-
ChunkExtra::new(state_root, vec![], 0, chain_genesis.gas_limit, 0, 0, 0),
258+
ChunkExtra::new(
259+
state_root,
260+
vec![],
261+
0,
262+
chain_genesis.gas_limit,
263+
0,
264+
0,
265+
0,
266+
),
251267
);
252268
}
253269

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

16541670
let any_transaction_is_invalid = chunk.transactions.iter().any(|t| {
1655-
self.chain_store_update.get_chain_store().check_blocks_on_same_chain(
1656-
&block.header,
1657-
&t.transaction.block_hash,
1658-
self.transaction_validity_period,
1659-
).is_err()
1671+
self.chain_store_update
1672+
.get_chain_store()
1673+
.check_blocks_on_same_chain(
1674+
&block.header,
1675+
&t.transaction.block_hash,
1676+
self.transaction_validity_period,
1677+
)
1678+
.is_err()
16601679
});
16611680
if any_transaction_is_invalid {
16621681
debug!(target: "chain", "Invalid transactions in the chunk: {:?}", chunk.transactions);
@@ -1693,7 +1712,7 @@ impl<'a> ChainUpdate<'a> {
16931712
gas_limit,
16941713
apply_result.total_rent_paid,
16951714
apply_result.total_validator_reward,
1696-
apply_result.total_balance_burnt
1715+
apply_result.total_balance_burnt,
16971716
),
16981717
);
16991718
// Save resulting receipts.
@@ -2200,7 +2219,7 @@ impl<'a> ChainUpdate<'a> {
22002219
gas_limit,
22012220
apply_result.total_rent_paid,
22022221
apply_result.total_validator_reward,
2203-
apply_result.total_balance_burnt
2222+
apply_result.total_balance_burnt,
22042223
);
22052224
self.chain_store_update.save_chunk_extra(&block_header.hash, shard_id, chunk_extra);
22062225

chain/chain/src/types.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -483,17 +483,22 @@ mod tests {
483483
use chrono::Utc;
484484

485485
use near_crypto::{InMemorySigner, KeyType, Signature};
486+
use near_primitives::block::genesis_chunks;
486487

487488
use super::*;
488489

489490
#[test]
490491
fn test_block_produce() {
491492
let num_shards = 32;
492-
let genesis = Block::genesis(
493+
let genesis_chunks = genesis_chunks(
493494
vec![StateRoot { hash: CryptoHash::default(), num_parts: 9 /* TODO MOO */ }],
494-
Utc::now(),
495495
num_shards,
496496
1_000_000,
497+
);
498+
let genesis = Block::genesis(
499+
genesis_chunks.into_iter().map(|chunk| chunk.header).collect(),
500+
Utc::now(),
501+
1_000_000,
497502
100,
498503
1_000_000_000,
499504
);

chain/client/src/types.rs

+1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ impl Message for GetBlock {
255255

256256
/// Actor message requesting a chunk by chunk hash and block hash + shard id.
257257
pub enum GetChunk {
258+
BlockHeight(BlockIndex, ShardId),
258259
BlockHash(CryptoHash, ShardId),
259260
ChunkHash(ChunkHash),
260261
}

chain/client/src/view_client.rs

+7
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ impl Handler<GetChunk> for ViewClientActor {
174174
.get_chunk(&block.chunks[shard_id as usize].chunk_hash())
175175
.map(Clone::clone)
176176
})
177+
},
178+
GetChunk::BlockHeight(block_height, shard_id) => {
179+
self.chain.get_block_by_height(block_height).map(Clone::clone).and_then(|block| {
180+
self.chain
181+
.get_chunk(&block.chunks[shard_id as usize].chunk_hash())
182+
.map(Clone::clone)
183+
})
177184
}
178185
}
179186
.map(|chunk| chunk.into())

chain/jsonrpc/client/src/lib.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use serde::Deserialize;
66
use serde::Serialize;
77

88
use near_primitives::hash::CryptoHash;
9-
use near_primitives::types::BlockIndex;
9+
use near_primitives::types::{BlockIndex, ShardId};
1010
use near_primitives::views::{
11-
BlockView, ExecutionOutcomeView, FinalExecutionOutcomeView, QueryResponse, StatusResponse,
11+
BlockView, ChunkView, ExecutionOutcomeView, FinalExecutionOutcomeView, QueryResponse, StatusResponse,
1212
};
1313

1414
use crate::message::{from_slice, Message};
@@ -22,6 +22,13 @@ pub enum BlockId {
2222
Hash(CryptoHash),
2323
}
2424

25+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26+
#[serde(untagged)]
27+
pub enum ChunkId {
28+
BlockShardId(BlockId, ShardId),
29+
Hash(CryptoHash),
30+
}
31+
2532
/// Timeout for establishing connection.
2633
const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
2734

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

185193
/// Create new JSON RPC client that connects to the given address.

chain/jsonrpc/src/lib.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ use async_utils::{delay, timeout};
1818
use message::Message;
1919
use message::{Request, RpcError};
2020
use near_client::{
21-
ClientActor, GetBlock, GetNetworkInfo, Query, Status, TxDetails, TxStatus, ViewClientActor,
21+
ClientActor, GetBlock, GetChunk, GetNetworkInfo, Query, Status, TxDetails, TxStatus, ViewClientActor,
2222
};
2323
pub use near_jsonrpc_client as client;
24-
use near_jsonrpc_client::{message, BlockId};
24+
use near_jsonrpc_client::{message, BlockId, ChunkId};
2525
use near_metrics::{Encoder, TextEncoder};
2626
use near_network::{NetworkClientMessages, NetworkClientResponses};
2727
use near_primitives::hash::CryptoHash;
@@ -142,6 +142,7 @@ impl JsonRpcHandler {
142142
"tx" => self.tx_status(request.params).await,
143143
"tx_details" => self.tx_details(request.params).await,
144144
"block" => self.block(request.params).await,
145+
"chunk" => self.chunk(request.params).await,
145146
"network_info" => self.network_info().await,
146147
_ => Err(RpcError::method_not_found(request.method)),
147148
}
@@ -238,6 +239,22 @@ impl JsonRpcHandler {
238239
)
239240
}
240241

242+
async fn chunk(&self, params: Option<Value>) -> Result<Value, RpcError> {
243+
let (chunk_id,) = parse_params::<(ChunkId,)>(params)?;
244+
jsonify(
245+
self.view_client_addr
246+
.send(match chunk_id {
247+
ChunkId::BlockShardId(block_id, shard_id) => match block_id {
248+
BlockId::Height(block_height) => GetChunk::BlockHeight(block_height, shard_id),
249+
BlockId::Hash(block_hash) => GetChunk::BlockHash(block_hash.into(), shard_id),
250+
},
251+
ChunkId::Hash(chunk_hash) => GetChunk::ChunkHash(chunk_hash.into()),
252+
})
253+
.compat()
254+
.await,
255+
)
256+
}
257+
241258
async fn network_info(&self) -> Result<Value, RpcError> {
242259
jsonify(self.client_addr.send(GetNetworkInfo {}).compat().await)
243260
}

chain/jsonrpc/tests/rpc_query.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ use actix::System;
44
use futures::future;
55
use futures::future::Future;
66

7+
use near_crypto::Signature;
78
use near_jsonrpc::client::new_client;
89
use near_jsonrpc::test_utils::start_all;
9-
use near_jsonrpc_client::BlockId;
10+
use near_jsonrpc_client::{BlockId, ChunkId};
1011
use near_primitives::hash::CryptoHash;
1112
use near_primitives::test_utils::init_test_logger;
13+
use near_primitives::types::ShardId;
1214

1315
/// Retrieve blocks via json rpc
1416
#[test]
@@ -65,6 +67,55 @@ fn test_block_by_hash() {
6567
.unwrap();
6668
}
6769

70+
/// Retrieve blocks via json rpc
71+
#[test]
72+
fn test_chunk_by_hash() {
73+
init_test_logger();
74+
75+
System::run(|| {
76+
let (_view_client_addr, addr) = start_all(true);
77+
78+
let mut client = new_client(&format!("http://{}", addr.clone()));
79+
actix::spawn(
80+
client.chunk(ChunkId::BlockShardId(BlockId::Height(0), ShardId::from(0u64))).then(
81+
move |chunk| {
82+
let chunk = chunk.unwrap();
83+
assert_eq!(chunk.header.balance_burnt, 0);
84+
assert_eq!(chunk.header.chunk_hash.as_ref().len(), 32);
85+
assert_eq!(chunk.header.encoded_length, 8);
86+
assert_eq!(chunk.header.encoded_merkle_root.as_ref().len(), 32);
87+
assert_eq!(chunk.header.gas_limit, 1000000);
88+
assert_eq!(chunk.header.gas_used, 0);
89+
assert_eq!(chunk.header.height_created, 0);
90+
assert_eq!(chunk.header.height_included, 0);
91+
assert_eq!(chunk.header.outgoing_receipts_root.as_ref().len(), 32);
92+
assert_eq!(chunk.header.prev_block_hash.as_ref().len(), 32);
93+
assert_eq!(chunk.header.prev_state_num_parts, 17);
94+
assert_eq!(chunk.header.prev_state_root_hash.as_ref().len(), 32);
95+
assert_eq!(chunk.header.rent_paid, 0);
96+
assert_eq!(chunk.header.shard_id, 0);
97+
assert!(if let Signature::ED25519(_) = chunk.header.signature {
98+
true
99+
} else {
100+
false
101+
});
102+
assert_eq!(chunk.header.tx_root.as_ref(), &[0; 32]);
103+
assert_eq!(chunk.header.validator_proposals, vec![]);
104+
assert_eq!(chunk.header.validator_reward, 0);
105+
let mut client = new_client(&format!("http://{}", addr));
106+
client.chunk(ChunkId::Hash(chunk.header.chunk_hash)).then(move |same_chunk| {
107+
let same_chunk = same_chunk.unwrap();
108+
assert_eq!(chunk.header.chunk_hash, same_chunk.header.chunk_hash);
109+
System::current().stop();
110+
future::ok(())
111+
})
112+
},
113+
),
114+
);
115+
})
116+
.unwrap();
117+
}
118+
68119
/// Connect to json rpc and query the client.
69120
#[test]
70121
fn test_query() {

core/primitives/benches/serialization.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use chrono::Utc;
99

1010
use near_crypto::{InMemorySigner, KeyType, PublicKey, Signature};
1111
use near_primitives::account::Account;
12-
use near_primitives::block::Block;
12+
use near_primitives::block::{genesis_chunks, Block};
1313
use near_primitives::hash::CryptoHash;
1414
use near_primitives::transaction::{Action, SignedTransaction, Transaction, TransferAction};
1515
use near_primitives::types::{EpochId, StateRoot};
@@ -33,11 +33,15 @@ fn create_transaction() -> SignedTransaction {
3333
}
3434

3535
fn create_block() -> Block {
36-
let genesis = Block::genesis(
36+
let genesis_chunks = genesis_chunks(
3737
vec![StateRoot { hash: CryptoHash::default(), num_parts: 1 /* TODO MOO */ }],
38-
Utc::now(),
3938
1,
4039
1_000,
40+
);
41+
let genesis = Block::genesis(
42+
genesis_chunks.into_iter().map(|chunk| chunk.header).collect(),
43+
Utc::now(),
44+
1_000,
4145
1_000,
4246
1_000,
4347
);

core/primitives/src/block.rs

+35-25
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use near_crypto::{EmptySigner, KeyType, PublicKey, Signature, Signer};
77

88
use crate::hash::{hash, CryptoHash};
99
use crate::merkle::merklize;
10-
use crate::sharding::{ChunkHashHeight, ShardChunkHeader};
10+
use crate::sharding::{ChunkHashHeight, EncodedShardChunk, ShardChunk, ShardChunkHeader};
1111
use crate::types::{
1212
Balance, BlockIndex, EpochId, Gas, MerkleHash, ShardId, StateRoot, ValidatorStake,
1313
};
@@ -242,38 +242,48 @@ pub struct Block {
242242
pub chunks: Vec<ShardChunkHeader>,
243243
}
244244

245+
pub fn genesis_chunks(
246+
state_roots: Vec<StateRoot>,
247+
num_shards: ShardId,
248+
initial_gas_limit: Gas,
249+
) -> Vec<ShardChunk> {
250+
assert!(state_roots.len() == 1 || state_roots.len() == (num_shards as usize));
251+
(0..num_shards)
252+
.map(|i| {
253+
let (encoded_chunk, _) = EncodedShardChunk::new(
254+
CryptoHash::default(),
255+
state_roots[i as usize % state_roots.len()].clone(),
256+
0,
257+
i,
258+
3,
259+
1,
260+
0,
261+
initial_gas_limit,
262+
0,
263+
0,
264+
0,
265+
CryptoHash::default(),
266+
vec![],
267+
&vec![],
268+
&vec![],
269+
CryptoHash::default(),
270+
&EmptySigner {},
271+
)
272+
.expect("Failed to decode genesis chunk");
273+
encoded_chunk.decode_chunk(1).expect("Failed to decode genesis chunk")
274+
})
275+
.collect()
276+
}
277+
245278
impl Block {
246279
/// Returns genesis block for given genesis date and state root.
247280
pub fn genesis(
248-
state_roots: Vec<StateRoot>,
281+
chunks: Vec<ShardChunkHeader>,
249282
timestamp: DateTime<Utc>,
250-
num_shards: ShardId,
251283
initial_gas_limit: Gas,
252284
initial_gas_price: Balance,
253285
initial_total_supply: Balance,
254286
) -> Self {
255-
assert!(state_roots.len() == 1 || state_roots.len() == (num_shards as usize));
256-
let chunks = (0..num_shards)
257-
.map(|i| {
258-
ShardChunkHeader::new(
259-
CryptoHash::default(),
260-
state_roots[i as usize % state_roots.len()].clone(),
261-
CryptoHash::default(),
262-
0,
263-
0,
264-
i,
265-
0,
266-
initial_gas_limit,
267-
0,
268-
0,
269-
0,
270-
CryptoHash::default(),
271-
CryptoHash::default(),
272-
vec![],
273-
&EmptySigner {},
274-
)
275-
})
276-
.collect();
277287
Block {
278288
header: BlockHeader::genesis(
279289
Block::compute_state_root(&chunks),

0 commit comments

Comments
 (0)