mirror of
				https://github.com/0glabs/0g-storage-node.git
				synced 2025-11-03 16:17:27 +00:00 
			
		
		
		
	Support mining on sharded storage. (#64)
* Change PoraHash compute * Change padSeed compute * Refactor * Support mining on sharded storage * Detect single core performance and set correct params for test * Fix clippy * Fix an overflow bug
This commit is contained in:
		
							parent
							
								
									193e154361
								
							
						
					
					
						commit
						2262bc3fb9
					
				@ -1 +1 @@
 | 
				
			|||||||
Subproject commit 6a9f52e8c10ff9b5cd7a5844c543c0951b97d395
 | 
					Subproject commit b11385532c3c12688bb6a279262e8e87da91a553
 | 
				
			||||||
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -8374,6 +8374,7 @@ dependencies = [
 | 
				
			|||||||
 "tracing",
 | 
					 "tracing",
 | 
				
			||||||
 "tracing-appender",
 | 
					 "tracing-appender",
 | 
				
			||||||
 "tracing-subscriber",
 | 
					 "tracing-subscriber",
 | 
				
			||||||
 | 
					 "zgs_spec",
 | 
				
			||||||
 "zgs_version",
 | 
					 "zgs_version",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ exit-future = "0.2.0"
 | 
				
			|||||||
futures = "0.3.21"
 | 
					futures = "0.3.21"
 | 
				
			||||||
file_location_cache = { path = "file_location_cache" }
 | 
					file_location_cache = { path = "file_location_cache" }
 | 
				
			||||||
zgs_version = { path = "../common/zgs_version" }
 | 
					zgs_version = { path = "../common/zgs_version" }
 | 
				
			||||||
 | 
					zgs_spec = { path = "../common/spec" }
 | 
				
			||||||
log_entry_sync = { path = "./log_entry_sync" }
 | 
					log_entry_sync = { path = "./log_entry_sync" }
 | 
				
			||||||
miner = { path = "./miner" }
 | 
					miner = { path = "./miner" }
 | 
				
			||||||
network = { path = "./network" }
 | 
					network = { path = "./network" }
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,95 @@ use ethers::providers::Middleware;
 | 
				
			|||||||
use ethers::providers::Provider;
 | 
					use ethers::providers::Provider;
 | 
				
			||||||
use ethers::signers::LocalWallet;
 | 
					use ethers::signers::LocalWallet;
 | 
				
			||||||
use ethers::signers::Signer;
 | 
					use ethers::signers::Signer;
 | 
				
			||||||
 | 
					use zgs_spec::BYTES_PER_LOAD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct ShardConfig {
 | 
				
			||||||
 | 
					    pub shard_group_load_chunks: usize,
 | 
				
			||||||
 | 
					    pub shard_id: usize,
 | 
				
			||||||
 | 
					    pub num_shard: usize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for ShardConfig {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            shard_group_load_chunks: 1,
 | 
				
			||||||
 | 
					            shard_id: 0,
 | 
				
			||||||
 | 
					            num_shard: 1,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ShardConfig {
 | 
				
			||||||
 | 
					    pub fn new(
 | 
				
			||||||
 | 
					        shard_group_bytes: Option<usize>,
 | 
				
			||||||
 | 
					        shard_position: &Option<String>,
 | 
				
			||||||
 | 
					    ) -> Result<Option<Self>, String> {
 | 
				
			||||||
 | 
					        let (group_bytes, (id, num)) = match (shard_group_bytes, shard_position) {
 | 
				
			||||||
 | 
					            (None, None) => {
 | 
				
			||||||
 | 
					                return Ok(None);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            (Some(bytes), Some(position)) => (bytes, Self::parse_position(position)?),
 | 
				
			||||||
 | 
					            _ => {
 | 
				
			||||||
 | 
					                return Err(
 | 
				
			||||||
 | 
					                    "`shard_group_bytes` and `shard_position` should be set simultaneously".into(),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if group_bytes < BYTES_PER_LOAD || group_bytes & (group_bytes - 1) != 0 {
 | 
				
			||||||
 | 
					            return Err(format!(
 | 
				
			||||||
 | 
					                "Incorrect shard group bytes: {}, should be power of two and >= {}",
 | 
				
			||||||
 | 
					                group_bytes, BYTES_PER_LOAD
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let group_chunks = group_bytes / BYTES_PER_LOAD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if id >= num {
 | 
				
			||||||
 | 
					            return Err(format!(
 | 
				
			||||||
 | 
					                "Incorrect shard_id: expected [0, {}), actual {}",
 | 
				
			||||||
 | 
					                num, id
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if group_chunks < num {
 | 
				
			||||||
 | 
					            return Err(format!("Incorrect shard_group_number: the shard group contains {} loading chunks, which cannot be divided into {} shards", group_chunks, num));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Some(ShardConfig {
 | 
				
			||||||
 | 
					            shard_group_load_chunks: group_chunks,
 | 
				
			||||||
 | 
					            shard_id: id,
 | 
				
			||||||
 | 
					            num_shard: num,
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn shard_chunks(&self) -> u64 {
 | 
				
			||||||
 | 
					        (self.shard_group_load_chunks / self.num_shard) as u64
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn shard_mask(&self) -> u64 {
 | 
				
			||||||
 | 
					        let x = self.shard_group_load_chunks as u64 - self.shard_chunks();
 | 
				
			||||||
 | 
					        !x
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn parse_position(input: &str) -> Result<(usize, usize), String> {
 | 
				
			||||||
 | 
					        let parts: Vec<&str> = input.trim().split('/').map(|s| s.trim()).collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if parts.len() != 2 {
 | 
				
			||||||
 | 
					            return Err("Incorrect format, expected like: '0 / 8'".into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let numerator = parts[0]
 | 
				
			||||||
 | 
					            .parse::<usize>()
 | 
				
			||||||
 | 
					            .map_err(|e| format!("Cannot parse shard position {:?}", e))?;
 | 
				
			||||||
 | 
					        let denominator = parts[1]
 | 
				
			||||||
 | 
					            .parse::<usize>()
 | 
				
			||||||
 | 
					            .map_err(|e| format!("Cannot parse shard position {:?}", e))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok((numerator, denominator))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct MinerConfig {
 | 
					pub struct MinerConfig {
 | 
				
			||||||
    pub(crate) miner_id: Option<H256>,
 | 
					    pub(crate) miner_id: Option<H256>,
 | 
				
			||||||
@ -16,6 +105,7 @@ pub struct MinerConfig {
 | 
				
			|||||||
    pub(crate) submission_gas: Option<U256>,
 | 
					    pub(crate) submission_gas: Option<U256>,
 | 
				
			||||||
    pub(crate) cpu_percentage: u64,
 | 
					    pub(crate) cpu_percentage: u64,
 | 
				
			||||||
    pub(crate) iter_batch: usize,
 | 
					    pub(crate) iter_batch: usize,
 | 
				
			||||||
 | 
					    pub(crate) shard_config: Option<ShardConfig>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type MineServiceMiddleware = SignerMiddleware<Provider<Http>, LocalWallet>;
 | 
					pub type MineServiceMiddleware = SignerMiddleware<Provider<Http>, LocalWallet>;
 | 
				
			||||||
@ -31,6 +121,7 @@ impl MinerConfig {
 | 
				
			|||||||
        submission_gas: Option<U256>,
 | 
					        submission_gas: Option<U256>,
 | 
				
			||||||
        cpu_percentage: u64,
 | 
					        cpu_percentage: u64,
 | 
				
			||||||
        iter_batch: usize,
 | 
					        iter_batch: usize,
 | 
				
			||||||
 | 
					        shard_config: Option<ShardConfig>,
 | 
				
			||||||
    ) -> Option<MinerConfig> {
 | 
					    ) -> Option<MinerConfig> {
 | 
				
			||||||
        miner_key.map(|miner_key| MinerConfig {
 | 
					        miner_key.map(|miner_key| MinerConfig {
 | 
				
			||||||
            miner_id,
 | 
					            miner_id,
 | 
				
			||||||
@ -41,6 +132,7 @@ impl MinerConfig {
 | 
				
			|||||||
            submission_gas,
 | 
					            submission_gas,
 | 
				
			||||||
            cpu_percentage,
 | 
					            cpu_percentage,
 | 
				
			||||||
            iter_batch,
 | 
					            iter_batch,
 | 
				
			||||||
 | 
					            shard_config,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,13 +9,14 @@ mod loader;
 | 
				
			|||||||
mod mine;
 | 
					mod mine;
 | 
				
			||||||
mod miner_id;
 | 
					mod miner_id;
 | 
				
			||||||
pub mod pora;
 | 
					pub mod pora;
 | 
				
			||||||
 | 
					mod recall_range;
 | 
				
			||||||
mod sealer;
 | 
					mod sealer;
 | 
				
			||||||
mod service;
 | 
					mod service;
 | 
				
			||||||
mod submitter;
 | 
					mod submitter;
 | 
				
			||||||
mod watcher;
 | 
					mod watcher;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use config::MinerConfig;
 | 
					pub use config::{MinerConfig, ShardConfig};
 | 
				
			||||||
pub use loader::PoraLoader;
 | 
					pub use loader::PoraLoader;
 | 
				
			||||||
pub use mine::CustomMineRange;
 | 
					pub use mine::MineRangeConfig;
 | 
				
			||||||
pub use miner_id::load_miner_id;
 | 
					pub use miner_id::load_miner_id;
 | 
				
			||||||
pub use service::{MineService, MinerMessage};
 | 
					pub use service::{MineService, MinerMessage};
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,8 @@ use tokio::time::{sleep, Duration, Instant};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use zgs_spec::{SECTORS_PER_LOAD, SECTORS_PER_MAX_MINING_RANGE, SECTORS_PER_PRICING};
 | 
					use zgs_spec::{SECTORS_PER_LOAD, SECTORS_PER_MAX_MINING_RANGE, SECTORS_PER_PRICING};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::recall_range::RecallRange;
 | 
				
			||||||
 | 
					use crate::ShardConfig;
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    pora::{AnswerWithoutProof, Miner},
 | 
					    pora::{AnswerWithoutProof, Miner},
 | 
				
			||||||
    watcher::MineContextMessage,
 | 
					    watcher::MineContextMessage,
 | 
				
			||||||
@ -23,7 +25,7 @@ pub struct PoraService {
 | 
				
			|||||||
    loader: Arc<dyn PoraLoader>,
 | 
					    loader: Arc<dyn PoraLoader>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    puzzle: Option<PoraPuzzle>,
 | 
					    puzzle: Option<PoraPuzzle>,
 | 
				
			||||||
    mine_range: CustomMineRange,
 | 
					    mine_range: MineRangeConfig,
 | 
				
			||||||
    miner_id: H256,
 | 
					    miner_id: H256,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpu_percentage: u64,
 | 
					    cpu_percentage: u64,
 | 
				
			||||||
@ -35,14 +37,15 @@ struct PoraPuzzle {
 | 
				
			|||||||
    target_quality: U256,
 | 
					    target_quality: U256,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#[derive(Clone, Copy, Debug, Default)]
 | 
					#[derive(Clone, Copy, Debug, Default)]
 | 
				
			||||||
pub struct CustomMineRange {
 | 
					pub struct MineRangeConfig {
 | 
				
			||||||
    start_position: Option<u64>,
 | 
					    start_position: Option<u64>,
 | 
				
			||||||
    end_position: Option<u64>,
 | 
					    end_position: Option<u64>,
 | 
				
			||||||
 | 
					    shard_config: Option<ShardConfig>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CustomMineRange {
 | 
					impl MineRangeConfig {
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    fn to_valid_range(self, context: &MineContext) -> Option<(u64, u64)> {
 | 
					    fn to_valid_range(self, context: &MineContext) -> Option<RecallRange> {
 | 
				
			||||||
        let self_start_position = self.start_position?;
 | 
					        let self_start_position = self.start_position?;
 | 
				
			||||||
        let self_end_position = self.end_position?;
 | 
					        let self_end_position = self.end_position?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -57,7 +60,15 @@ impl CustomMineRange {
 | 
				
			|||||||
        let start_position = std::cmp::min(self_start_position, minable_length - mining_length);
 | 
					        let start_position = std::cmp::min(self_start_position, minable_length - mining_length);
 | 
				
			||||||
        let start_position =
 | 
					        let start_position =
 | 
				
			||||||
            (start_position / SECTORS_PER_PRICING as u64) * SECTORS_PER_PRICING as u64;
 | 
					            (start_position / SECTORS_PER_PRICING as u64) * SECTORS_PER_PRICING as u64;
 | 
				
			||||||
        Some((start_position, mining_length))
 | 
					
 | 
				
			||||||
 | 
					        Some(RecallRange {
 | 
				
			||||||
 | 
					            start_position,
 | 
				
			||||||
 | 
					            mining_length,
 | 
				
			||||||
 | 
					            shard_mask: self.shard_config.map_or(u64::MAX, |c| c.shard_mask()),
 | 
				
			||||||
 | 
					            shard_id: self
 | 
				
			||||||
 | 
					                .shard_config
 | 
				
			||||||
 | 
					                .map_or(0, |c| c.shard_id as u64 * c.shard_chunks()),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
@ -86,9 +97,10 @@ impl PoraService {
 | 
				
			|||||||
    ) -> mpsc::UnboundedReceiver<AnswerWithoutProof> {
 | 
					    ) -> mpsc::UnboundedReceiver<AnswerWithoutProof> {
 | 
				
			||||||
        let (mine_answer_sender, mine_answer_receiver) =
 | 
					        let (mine_answer_sender, mine_answer_receiver) =
 | 
				
			||||||
            mpsc::unbounded_channel::<AnswerWithoutProof>();
 | 
					            mpsc::unbounded_channel::<AnswerWithoutProof>();
 | 
				
			||||||
        let mine_range = CustomMineRange {
 | 
					        let mine_range = MineRangeConfig {
 | 
				
			||||||
            start_position: Some(0),
 | 
					            start_position: Some(0),
 | 
				
			||||||
            end_position: Some(u64::MAX),
 | 
					            end_position: Some(u64::MAX),
 | 
				
			||||||
 | 
					            shard_config: config.shard_config,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let pora = PoraService {
 | 
					        let pora = PoraService {
 | 
				
			||||||
            mine_context_receiver,
 | 
					            mine_context_receiver,
 | 
				
			||||||
@ -180,19 +192,18 @@ impl PoraService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    fn as_miner(&self) -> Option<Miner> {
 | 
					    fn as_miner(&self) -> Option<Miner> {
 | 
				
			||||||
        match self.puzzle.as_ref() {
 | 
					        let puzzle = self.puzzle.as_ref()?;
 | 
				
			||||||
            Some(puzzle) => self.mine_range.to_valid_range(&puzzle.context).map(
 | 
					
 | 
				
			||||||
                |(start_position, mining_length)| Miner {
 | 
					        let range = self.mine_range.to_valid_range(&puzzle.context)?;
 | 
				
			||||||
                    start_position,
 | 
					        (range.mining_length > 0).then_some(())?;
 | 
				
			||||||
                    mining_length,
 | 
					
 | 
				
			||||||
                    miner_id: &self.miner_id,
 | 
					        Some(Miner {
 | 
				
			||||||
                    custom_mine_range: &self.mine_range,
 | 
					            range,
 | 
				
			||||||
                    context: &puzzle.context,
 | 
					            miner_id: &self.miner_id,
 | 
				
			||||||
                    target_quality: &puzzle.target_quality,
 | 
					            mine_range_config: &self.mine_range,
 | 
				
			||||||
                    loader: &*self.loader,
 | 
					            context: &puzzle.context,
 | 
				
			||||||
                },
 | 
					            target_quality: &puzzle.target_quality,
 | 
				
			||||||
            ),
 | 
					            loader: &*self.loader,
 | 
				
			||||||
            _ => None,
 | 
					        })
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
use crate::{CustomMineRange, PoraLoader};
 | 
					use crate::recall_range::RecallRange;
 | 
				
			||||||
 | 
					use crate::{MineRangeConfig, PoraLoader};
 | 
				
			||||||
use blake2::{Blake2b512, Digest};
 | 
					use blake2::{Blake2b512, Digest};
 | 
				
			||||||
use contract_interface::zgs_flow::MineContext;
 | 
					use contract_interface::zgs_flow::MineContext;
 | 
				
			||||||
use ethereum_types::{H256, U256};
 | 
					use ethereum_types::{H256, U256};
 | 
				
			||||||
@ -18,13 +19,12 @@ fn keccak(input: impl AsRef<[u8]>) -> [u8; KECCAK256_OUTPUT_BYTES] {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) struct Miner<'a> {
 | 
					pub(crate) struct Miner<'a> {
 | 
				
			||||||
    pub start_position: u64,
 | 
					    pub range: RecallRange,
 | 
				
			||||||
    pub mining_length: u64,
 | 
					 | 
				
			||||||
    pub miner_id: &'a H256,
 | 
					    pub miner_id: &'a H256,
 | 
				
			||||||
    pub context: &'a MineContext,
 | 
					    pub context: &'a MineContext,
 | 
				
			||||||
    pub target_quality: &'a U256,
 | 
					    pub target_quality: &'a U256,
 | 
				
			||||||
    pub loader: &'a dyn PoraLoader,
 | 
					    pub loader: &'a dyn PoraLoader,
 | 
				
			||||||
    pub custom_mine_range: &'a CustomMineRange,
 | 
					    pub mine_range_config: &'a MineRangeConfig,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct AnswerWithoutProof {
 | 
					pub struct AnswerWithoutProof {
 | 
				
			||||||
@ -32,8 +32,7 @@ pub struct AnswerWithoutProof {
 | 
				
			|||||||
    pub context_flow_root: H256,
 | 
					    pub context_flow_root: H256,
 | 
				
			||||||
    pub nonce: H256,
 | 
					    pub nonce: H256,
 | 
				
			||||||
    pub miner_id: H256,
 | 
					    pub miner_id: H256,
 | 
				
			||||||
    pub start_position: u64,
 | 
					    pub range: RecallRange,
 | 
				
			||||||
    pub mining_length: u64,
 | 
					 | 
				
			||||||
    pub recall_position: u64,
 | 
					    pub recall_position: u64,
 | 
				
			||||||
    pub seal_offset: usize,
 | 
					    pub seal_offset: usize,
 | 
				
			||||||
    pub sealed_data: [u8; BYTES_PER_SEAL],
 | 
					    pub sealed_data: [u8; BYTES_PER_SEAL],
 | 
				
			||||||
@ -59,24 +58,21 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn iteration(&self, nonce: H256) -> Option<AnswerWithoutProof> {
 | 
					    pub async fn iteration(&self, nonce: H256) -> Option<AnswerWithoutProof> {
 | 
				
			||||||
        let (scratch_pad, recall_seed) = self.make_scratch_pad(&nonce);
 | 
					        let ScratchPad {
 | 
				
			||||||
 | 
					            scratch_pad,
 | 
				
			||||||
 | 
					            recall_seed,
 | 
				
			||||||
 | 
					            pad_seed,
 | 
				
			||||||
 | 
					        } = self.make_scratch_pad(&nonce);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.mining_length == 0 {
 | 
					        if self.range.mining_length == 0 {
 | 
				
			||||||
            return None;
 | 
					            return None;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let (_, recall_offset) = U256::from_big_endian(&recall_seed)
 | 
					        let recall_position = self.range.load_position(recall_seed)?;
 | 
				
			||||||
            .div_mod(U256::from((self.mining_length as usize) / SECTORS_PER_LOAD));
 | 
					        if !self.mine_range_config.is_covered(recall_position).unwrap() {
 | 
				
			||||||
        let recall_offset = recall_offset.as_u64();
 | 
					 | 
				
			||||||
        if !self
 | 
					 | 
				
			||||||
            .custom_mine_range
 | 
					 | 
				
			||||||
            .is_covered(self.start_position + recall_offset * SECTORS_PER_LOAD as u64)
 | 
					 | 
				
			||||||
            .unwrap()
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            trace!(
 | 
					            trace!(
 | 
				
			||||||
                "recall offset not in range: recall_offset={}, range={:?}",
 | 
					                "recall offset not in range: recall_offset={}",
 | 
				
			||||||
                recall_offset,
 | 
					                recall_position,
 | 
				
			||||||
                self.custom_mine_range
 | 
					 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            return None;
 | 
					            return None;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -86,7 +82,7 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
            avalibilities,
 | 
					            avalibilities,
 | 
				
			||||||
        } = self
 | 
					        } = self
 | 
				
			||||||
            .loader
 | 
					            .loader
 | 
				
			||||||
            .load_sealed_data(self.start_position / SECTORS_PER_LOAD as u64 + recall_offset)
 | 
					            .load_sealed_data(recall_position / SECTORS_PER_LOAD as u64)
 | 
				
			||||||
            .await?;
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let scratch_pad: [[u8; BYTES_PER_SEAL]; BYTES_PER_SCRATCHPAD / BYTES_PER_SEAL] =
 | 
					        let scratch_pad: [[u8; BYTES_PER_SEAL]; BYTES_PER_SCRATCHPAD / BYTES_PER_SEAL] =
 | 
				
			||||||
@ -104,8 +100,9 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
                *x ^= y;
 | 
					                *x ^= y;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let quality = self.pora(idx, &nonce, &sealed_data);
 | 
					            let quality = self.pora(idx, &sealed_data, pad_seed);
 | 
				
			||||||
            if &quality <= self.target_quality {
 | 
					            let quality_scale = self.range.shard_mask.count_zeros();
 | 
				
			||||||
 | 
					            if quality << quality_scale <= *self.target_quality {
 | 
				
			||||||
                debug!("Find a PoRA valid answer, quality: {}", quality);
 | 
					                debug!("Find a PoRA valid answer, quality: {}", quality);
 | 
				
			||||||
                // Undo mix data when find a valid solition
 | 
					                // Undo mix data when find a valid solition
 | 
				
			||||||
                for (x, y) in sealed_data.iter_mut().zip(scratch_pad.iter()) {
 | 
					                for (x, y) in sealed_data.iter_mut().zip(scratch_pad.iter()) {
 | 
				
			||||||
@ -116,11 +113,8 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
                    context_flow_root: self.context.flow_root.into(),
 | 
					                    context_flow_root: self.context.flow_root.into(),
 | 
				
			||||||
                    nonce,
 | 
					                    nonce,
 | 
				
			||||||
                    miner_id: *self.miner_id,
 | 
					                    miner_id: *self.miner_id,
 | 
				
			||||||
                    start_position: self.start_position,
 | 
					                    range: self.range,
 | 
				
			||||||
                    mining_length: self.mining_length,
 | 
					                    recall_position: recall_position + idx as u64 * SECTORS_PER_SEAL as u64,
 | 
				
			||||||
                    recall_position: self.start_position
 | 
					 | 
				
			||||||
                        + recall_offset * SECTORS_PER_LOAD as u64
 | 
					 | 
				
			||||||
                        + idx as u64 * SECTORS_PER_SEAL as u64,
 | 
					 | 
				
			||||||
                    seal_offset: idx,
 | 
					                    seal_offset: idx,
 | 
				
			||||||
                    sealed_data,
 | 
					                    sealed_data,
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
@ -129,25 +123,18 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
        None
 | 
					        None
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn make_scratch_pad(
 | 
					    fn make_scratch_pad(&self, nonce: &H256) -> ScratchPad {
 | 
				
			||||||
        &self,
 | 
					 | 
				
			||||||
        nonce: &H256,
 | 
					 | 
				
			||||||
    ) -> ([u8; BYTES_PER_SCRATCHPAD], [u8; KECCAK256_OUTPUT_BYTES]) {
 | 
					 | 
				
			||||||
        let mut digest: [u8; BLAKE2B_OUTPUT_BYTES] = {
 | 
					        let mut digest: [u8; BLAKE2B_OUTPUT_BYTES] = {
 | 
				
			||||||
            let mut hasher = Blake2b512::new();
 | 
					            let mut hasher = Blake2b512::new();
 | 
				
			||||||
            hasher.update(self.miner_id);
 | 
					            hasher.update(self.miner_id);
 | 
				
			||||||
            hasher.update(nonce);
 | 
					            hasher.update(nonce);
 | 
				
			||||||
            hasher.update(self.context.digest);
 | 
					            hasher.update(self.context.digest);
 | 
				
			||||||
 | 
					            hasher.update(self.range.digest());
 | 
				
			||||||
            hasher.update([0u8; 24]);
 | 
					 | 
				
			||||||
            hasher.update(self.start_position.to_be_bytes());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            hasher.update([0u8; 24]);
 | 
					 | 
				
			||||||
            hasher.update(self.mining_length.to_be_bytes());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            hasher.finalize().into()
 | 
					            hasher.finalize().into()
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let pad_seed = digest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut scratch_pad =
 | 
					        let mut scratch_pad =
 | 
				
			||||||
            [[0u8; BLAKE2B_OUTPUT_BYTES]; BYTES_PER_SCRATCHPAD / BLAKE2B_OUTPUT_BYTES];
 | 
					            [[0u8; BLAKE2B_OUTPUT_BYTES]; BYTES_PER_SCRATCHPAD / BLAKE2B_OUTPUT_BYTES];
 | 
				
			||||||
        for scratch_pad_cell in scratch_pad.iter_mut() {
 | 
					        for scratch_pad_cell in scratch_pad.iter_mut() {
 | 
				
			||||||
@ -158,26 +145,27 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
        let scratch_pad: [u8; BYTES_PER_SCRATCHPAD] = unsafe { std::mem::transmute(scratch_pad) };
 | 
					        let scratch_pad: [u8; BYTES_PER_SCRATCHPAD] = unsafe { std::mem::transmute(scratch_pad) };
 | 
				
			||||||
        let recall_seed: [u8; KECCAK256_OUTPUT_BYTES] = keccak(digest);
 | 
					        let recall_seed: [u8; KECCAK256_OUTPUT_BYTES] = keccak(digest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (scratch_pad, recall_seed)
 | 
					        ScratchPad {
 | 
				
			||||||
 | 
					            scratch_pad,
 | 
				
			||||||
 | 
					            recall_seed,
 | 
				
			||||||
 | 
					            pad_seed,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[inline]
 | 
					    #[inline]
 | 
				
			||||||
    fn pora(&self, seal_index: usize, nonce: &H256, mixed_data: &[u8; BYTES_PER_SEAL]) -> U256 {
 | 
					    fn pora(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        seal_index: usize,
 | 
				
			||||||
 | 
					        mixed_data: &[u8; BYTES_PER_SEAL],
 | 
				
			||||||
 | 
					        pad_seed: [u8; BLAKE2B_OUTPUT_BYTES],
 | 
				
			||||||
 | 
					    ) -> U256 {
 | 
				
			||||||
        let mut hasher = Blake2b512::new();
 | 
					        let mut hasher = Blake2b512::new();
 | 
				
			||||||
        hasher.update([0u8; 24]);
 | 
					        hasher.update([0u8; 24]);
 | 
				
			||||||
        hasher.update(seal_index.to_be_bytes());
 | 
					        hasher.update(seal_index.to_be_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        hasher.update(self.miner_id);
 | 
					        hasher.update(pad_seed);
 | 
				
			||||||
        hasher.update(nonce);
 | 
					        hasher.update([0u8; 32]);
 | 
				
			||||||
        hasher.update(self.context.digest);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        hasher.update([0u8; 24]);
 | 
					 | 
				
			||||||
        hasher.update(self.start_position.to_be_bytes());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        hasher.update([0u8; 24]);
 | 
					 | 
				
			||||||
        hasher.update(self.mining_length.to_be_bytes());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        hasher.update([0u8; 64]);
 | 
					 | 
				
			||||||
        hasher.update(mixed_data);
 | 
					        hasher.update(mixed_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let digest = hasher.finalize();
 | 
					        let digest = hasher.finalize();
 | 
				
			||||||
@ -185,3 +173,9 @@ impl<'a> Miner<'a> {
 | 
				
			|||||||
        U256::from_big_endian(&digest[0..32])
 | 
					        U256::from_big_endian(&digest[0..32])
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ScratchPad {
 | 
				
			||||||
 | 
					    scratch_pad: [u8; BYTES_PER_SCRATCHPAD],
 | 
				
			||||||
 | 
					    recall_seed: [u8; KECCAK256_OUTPUT_BYTES],
 | 
				
			||||||
 | 
					    pad_seed: [u8; BLAKE2B_OUTPUT_BYTES],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										52
									
								
								node/miner/src/recall_range.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								node/miner/src/recall_range.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					use ethereum_types::U256;
 | 
				
			||||||
 | 
					use tiny_keccak::{Hasher, Keccak};
 | 
				
			||||||
 | 
					use zgs_spec::SECTORS_PER_LOAD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(PartialEq, Eq, Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct RecallRange {
 | 
				
			||||||
 | 
					    pub start_position: u64,
 | 
				
			||||||
 | 
					    pub mining_length: u64,
 | 
				
			||||||
 | 
					    pub shard_mask: u64,
 | 
				
			||||||
 | 
					    pub shard_id: u64,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RecallRange {
 | 
				
			||||||
 | 
					    pub fn digest(&self) -> [u8; 32] {
 | 
				
			||||||
 | 
					        let mut hasher = Keccak::v256();
 | 
				
			||||||
 | 
					        hasher.update(&[0u8; 24]);
 | 
				
			||||||
 | 
					        hasher.update(&self.start_position.to_be_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hasher.update(&[0u8; 24]);
 | 
				
			||||||
 | 
					        hasher.update(&self.mining_length.to_be_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hasher.update(&[0u8; 24]);
 | 
				
			||||||
 | 
					        hasher.update(&self.shard_id.to_be_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hasher.update(&[0u8; 24]);
 | 
				
			||||||
 | 
					        hasher.update(&self.shard_mask.to_be_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut output = [0u8; 32];
 | 
				
			||||||
 | 
					        hasher.finalize(&mut output);
 | 
				
			||||||
 | 
					        output
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn load_position(&self, seed: [u8; 32]) -> Option<u64> {
 | 
				
			||||||
 | 
					        let (_, origin_recall_offset) = U256::from_big_endian(&seed)
 | 
				
			||||||
 | 
					            .div_mod(U256::from((self.mining_length as usize) / SECTORS_PER_LOAD));
 | 
				
			||||||
 | 
					        let origin_recall_offset = origin_recall_offset.as_u64();
 | 
				
			||||||
 | 
					        let recall_offset = (origin_recall_offset & self.shard_mask) | self.shard_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Some(self.start_position + recall_offset * SECTORS_PER_LOAD as u64)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<RecallRange> for contract_interface::RecallRange {
 | 
				
			||||||
 | 
					    fn from(value: RecallRange) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            start_position: value.start_position.into(),
 | 
				
			||||||
 | 
					            mine_length: value.mining_length.into(),
 | 
				
			||||||
 | 
					            shard_mask: value.shard_mask,
 | 
				
			||||||
 | 
					            shard_id: value.shard_id,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -93,8 +93,7 @@ impl Submitter {
 | 
				
			|||||||
            context_digest: mine_answer.context_digest.0,
 | 
					            context_digest: mine_answer.context_digest.0,
 | 
				
			||||||
            nonce: mine_answer.nonce.0,
 | 
					            nonce: mine_answer.nonce.0,
 | 
				
			||||||
            miner_id: mine_answer.miner_id.0,
 | 
					            miner_id: mine_answer.miner_id.0,
 | 
				
			||||||
            start_position: mine_answer.start_position.into(),
 | 
					            range: mine_answer.range.into(),
 | 
				
			||||||
            mine_length: mine_answer.mining_length.into(),
 | 
					 | 
				
			||||||
            recall_position: mine_answer.recall_position.into(),
 | 
					            recall_position: mine_answer.recall_position.into(),
 | 
				
			||||||
            seal_offset: mine_answer.seal_offset.into(),
 | 
					            seal_offset: mine_answer.seal_offset.into(),
 | 
				
			||||||
            sealed_context_digest: sealed_context_digest.digest,
 | 
					            sealed_context_digest: sealed_context_digest.digest,
 | 
				
			||||||
 | 
				
			|||||||
@ -105,13 +105,6 @@ impl MineContextWatcher {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn query_recent_context(&mut self) -> Result<(), String> {
 | 
					    async fn query_recent_context(&mut self) -> Result<(), String> {
 | 
				
			||||||
        // let mut watcher = self
 | 
					 | 
				
			||||||
        //     .provider
 | 
					 | 
				
			||||||
        //     .watch_blocks()
 | 
					 | 
				
			||||||
        //     .await
 | 
					 | 
				
			||||||
        //     .expect("should success")
 | 
					 | 
				
			||||||
        //     .stream();
 | 
					 | 
				
			||||||
        // watcher.next().await
 | 
					 | 
				
			||||||
        let context_call = self.flow_contract.make_context_with_result();
 | 
					        let context_call = self.flow_contract.make_context_with_result();
 | 
				
			||||||
        let epoch_call = self.mine_contract.last_mined_epoch();
 | 
					        let epoch_call = self.mine_contract.last_mined_epoch();
 | 
				
			||||||
        let quality_call = self.mine_contract.target_quality();
 | 
					        let quality_call = self.mine_contract.target_quality();
 | 
				
			||||||
@ -120,21 +113,18 @@ impl MineContextWatcher {
 | 
				
			|||||||
            try_join!(context_call.call(), epoch_call.call(), quality_call.call())
 | 
					            try_join!(context_call.call(), epoch_call.call(), quality_call.call())
 | 
				
			||||||
                .map_err(|e| format!("Failed to query mining context: {:?}", e))?;
 | 
					                .map_err(|e| format!("Failed to query mining context: {:?}", e))?;
 | 
				
			||||||
        let report = if context.epoch > epoch && context.digest != EMPTY_HASH.0 {
 | 
					        let report = if context.epoch > epoch && context.digest != EMPTY_HASH.0 {
 | 
				
			||||||
            if context.block_digest == [0; 32] {
 | 
					            Some((context, quality))
 | 
				
			||||||
                warn!("Mine Context is not updated on time.");
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                Some((context, quality))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            None
 | 
					            None
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if report != self.last_report {
 | 
					        if report == self.last_report {
 | 
				
			||||||
            self.mine_context_sender
 | 
					            return Ok(());
 | 
				
			||||||
                .send(report.clone())
 | 
					 | 
				
			||||||
                .map_err(|e| format!("Failed to send out the most recent mine context: {:?}", e))?;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.mine_context_sender
 | 
				
			||||||
 | 
					            .send(report.clone())
 | 
				
			||||||
 | 
					            .map_err(|e| format!("Failed to send out the most recent mine context: {:?}", e))?;
 | 
				
			||||||
        self.last_report = report;
 | 
					        self.last_report = report;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
use crate::ZgsConfig;
 | 
					use crate::ZgsConfig;
 | 
				
			||||||
use ethereum_types::{H256, U256};
 | 
					use ethereum_types::{H256, U256};
 | 
				
			||||||
use log_entry_sync::{CacheConfig, ContractAddress, LogSyncConfig};
 | 
					use log_entry_sync::{CacheConfig, ContractAddress, LogSyncConfig};
 | 
				
			||||||
use miner::MinerConfig;
 | 
					use miner::{MinerConfig, ShardConfig};
 | 
				
			||||||
use network::NetworkConfig;
 | 
					use network::NetworkConfig;
 | 
				
			||||||
use rpc::RPCConfig;
 | 
					use rpc::RPCConfig;
 | 
				
			||||||
use storage::StorageConfig;
 | 
					use storage::StorageConfig;
 | 
				
			||||||
@ -142,6 +142,9 @@ impl ZgsConfig {
 | 
				
			|||||||
        let submission_gas = self.miner_submission_gas.map(U256::from);
 | 
					        let submission_gas = self.miner_submission_gas.map(U256::from);
 | 
				
			||||||
        let cpu_percentage = self.miner_cpu_percentage;
 | 
					        let cpu_percentage = self.miner_cpu_percentage;
 | 
				
			||||||
        let iter_batch = self.mine_iter_batch_size;
 | 
					        let iter_batch = self.mine_iter_batch_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let shard_config = ShardConfig::new(self.shard_group_bytes, &self.shard_position)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(MinerConfig::new(
 | 
					        Ok(MinerConfig::new(
 | 
				
			||||||
            miner_id,
 | 
					            miner_id,
 | 
				
			||||||
            miner_key,
 | 
					            miner_key,
 | 
				
			||||||
@ -151,6 +154,7 @@ impl ZgsConfig {
 | 
				
			|||||||
            submission_gas,
 | 
					            submission_gas,
 | 
				
			||||||
            cpu_percentage,
 | 
					            cpu_percentage,
 | 
				
			||||||
            iter_batch,
 | 
					            iter_batch,
 | 
				
			||||||
 | 
					            shard_config,
 | 
				
			||||||
        ))
 | 
					        ))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -66,6 +66,8 @@ build_config! {
 | 
				
			|||||||
    (miner_submission_gas, (Option<u64>), None)
 | 
					    (miner_submission_gas, (Option<u64>), None)
 | 
				
			||||||
    (miner_cpu_percentage, (u64), 100)
 | 
					    (miner_cpu_percentage, (u64), 100)
 | 
				
			||||||
    (mine_iter_batch_size, (usize), 100)
 | 
					    (mine_iter_batch_size, (usize), 100)
 | 
				
			||||||
 | 
					    (shard_group_bytes, (Option<usize>), None)
 | 
				
			||||||
 | 
					    (shard_position, (Option<String>), None)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Default, Deserialize)]
 | 
					#[derive(Debug, Default, Deserialize)]
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
from test_framework.test_framework import TestFramework
 | 
					from test_framework.test_framework import TestFramework
 | 
				
			||||||
from config.node_config import MINER_ID, GENESIS_PRIV_KEY
 | 
					from config.node_config import MINER_ID, GENESIS_PRIV_KEY
 | 
				
			||||||
from utility.submission import create_submission, submit_data
 | 
					from utility.submission import create_submission, submit_data
 | 
				
			||||||
from utility.utils import wait_until
 | 
					from utility.utils import wait_until, estimate_st_performance
 | 
				
			||||||
from test_framework.blockchain_node import BlockChainNodeType
 | 
					from test_framework.blockchain_node import BlockChainNodeType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,8 +13,9 @@ class MineTest(TestFramework):
 | 
				
			|||||||
        self.zgs_node_configs[0] = {
 | 
					        self.zgs_node_configs[0] = {
 | 
				
			||||||
            "miner_key": GENESIS_PRIV_KEY,
 | 
					            "miner_key": GENESIS_PRIV_KEY,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.mine_period = int(45 / self.block_time)
 | 
					        self.mine_period = int(20 / self.block_time)
 | 
				
			||||||
        self.launch_wait_seconds = 15
 | 
					        self.launch_wait_seconds = 15
 | 
				
			||||||
 | 
					        self.log.info("Contract Info: Est. block time %.2f, Mine period %d", self.block_time, self.mine_period)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def submit_data(self, item, size):
 | 
					    def submit_data(self, item, size):
 | 
				
			||||||
        submissions_before = self.contract.num_submissions()
 | 
					        submissions_before = self.contract.num_submissions()
 | 
				
			||||||
@ -34,27 +35,34 @@ class MineTest(TestFramework):
 | 
				
			|||||||
        self.log.info("flow address: %s", self.contract.address())
 | 
					        self.log.info("flow address: %s", self.contract.address())
 | 
				
			||||||
        self.log.info("mine address: %s", self.mine_contract.address())
 | 
					        self.log.info("mine address: %s", self.mine_contract.address())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        quality = int(2**256 / 40960)
 | 
					        quality = int(2**256 / 400 / estimate_st_performance())
 | 
				
			||||||
        self.mine_contract.set_quality(quality)
 | 
					        self.mine_contract.set_quality(quality)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Submit the first data chunk")
 | 
					        self.log.info("Submit the first data chunk")
 | 
				
			||||||
        self.submit_data(b"\x11", 2000)
 | 
					        self.submit_data(b"\x11", 2000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        start_epoch = self.contract.epoch()
 | 
				
			||||||
 | 
					        self.log.info("Submission done, current epoch is %d", start_epoch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Wait for the first mine context release")
 | 
					        self.log.info("Wait for the first mine context release")
 | 
				
			||||||
        wait_until(lambda: int(blockchain.eth_blockNumber(), 16) > self.mine_period, timeout=180)
 | 
					        wait_until(lambda: int(blockchain.eth_blockNumber(), 16) >= start_epoch + 1, timeout=180)
 | 
				
			||||||
 | 
					        self.contract.update_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Wait for the first mine answer")
 | 
					        self.log.info("Wait for the first mine answer")
 | 
				
			||||||
        wait_until(lambda: self.mine_contract.last_mined_epoch() == 1)
 | 
					        wait_until(lambda: self.mine_contract.last_mined_epoch() == 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Wait for the second mine context release")
 | 
					        self.log.info("Wait for the second mine context release")
 | 
				
			||||||
        wait_until(lambda: int(blockchain.eth_blockNumber(), 16) > 2 * self.mine_period, timeout=180)
 | 
					        wait_until(lambda: int(blockchain.eth_blockNumber(), 16) >= start_epoch + 2, timeout=180)
 | 
				
			||||||
 | 
					        self.contract.update_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Wait for the second mine answer")
 | 
					        self.log.info("Wait for the second mine answer")
 | 
				
			||||||
        wait_until(lambda: self.mine_contract.last_mined_epoch() == 2)
 | 
					        wait_until(lambda: self.mine_contract.last_mined_epoch() == 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.nodes[0].miner_stop()
 | 
					        self.nodes[0].miner_stop()
 | 
				
			||||||
        self.log.info("Wait for the third mine context release")
 | 
					        self.log.info("Wait for the third mine context release")
 | 
				
			||||||
        wait_until(lambda: int(blockchain.eth_blockNumber(), 16) > 3 * self.mine_period, timeout=180)
 | 
					        wait_until(lambda: int(blockchain.eth_blockNumber(), 16) >= start_epoch + 3, timeout=180)
 | 
				
			||||||
 | 
					        self.contract.update_context()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        self.log.info("Submit the second data chunk")
 | 
					        self.log.info("Submit the second data chunk")
 | 
				
			||||||
        self.submit_data(b"\x22", 2000)
 | 
					        self.submit_data(b"\x22", 2000)
 | 
				
			||||||
        # Now the storage node should have the latest flow, but the mining context is using an old one.
 | 
					        # Now the storage node should have the latest flow, but the mining context is using an old one.
 | 
				
			||||||
@ -65,4 +73,4 @@ class MineTest(TestFramework):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    MineTest().main()
 | 
					    MineTest(blockchain_node_type=BlockChainNodeType.BSC).main()
 | 
				
			||||||
 | 
				
			|||||||
@ -2,9 +2,9 @@
 | 
				
			|||||||
from test_framework.test_framework import TestFramework
 | 
					from test_framework.test_framework import TestFramework
 | 
				
			||||||
from config.node_config import MINER_ID, GENESIS_PRIV_KEY
 | 
					from config.node_config import MINER_ID, GENESIS_PRIV_KEY
 | 
				
			||||||
from utility.submission import create_submission, submit_data
 | 
					from utility.submission import create_submission, submit_data
 | 
				
			||||||
from utility.utils import wait_until, assert_equal, assert_greater_than
 | 
					from utility.utils import wait_until, assert_equal, assert_greater_than, estimate_st_performance
 | 
				
			||||||
from test_framework.blockchain_node import BlockChainNodeType
 | 
					from test_framework.blockchain_node import BlockChainNodeType
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import math
 | 
					import math
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -16,10 +16,13 @@ class MineTest(TestFramework):
 | 
				
			|||||||
        self.num_nodes = 1
 | 
					        self.num_nodes = 1
 | 
				
			||||||
        self.zgs_node_configs[0] = {
 | 
					        self.zgs_node_configs[0] = {
 | 
				
			||||||
            "miner_key": GENESIS_PRIV_KEY,
 | 
					            "miner_key": GENESIS_PRIV_KEY,
 | 
				
			||||||
 | 
					            "shard_group_bytes": 4 * 1024 * 1024,
 | 
				
			||||||
 | 
					            "shard_position": "3 / 8",
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.enable_market = True
 | 
					        self.enable_market = True
 | 
				
			||||||
        self.mine_period = int(60 / self.block_time)
 | 
					        self.mine_period = int(45 / self.block_time)
 | 
				
			||||||
        self.launch_wait_seconds = 15
 | 
					        self.launch_wait_seconds = 15
 | 
				
			||||||
 | 
					        self.log.info("Contract Info: Est. block time %.2f, Mine period %d", self.block_time, self.mine_period)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def submit_data(self, item, size, no_submit = False):
 | 
					    def submit_data(self, item, size, no_submit = False):
 | 
				
			||||||
@ -42,7 +45,7 @@ class MineTest(TestFramework):
 | 
				
			|||||||
        self.log.info("flow address: %s", self.contract.address())
 | 
					        self.log.info("flow address: %s", self.contract.address())
 | 
				
			||||||
        self.log.info("mine address: %s", self.mine_contract.address())
 | 
					        self.log.info("mine address: %s", self.mine_contract.address())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        quality = int(2**256 / 4096)
 | 
					        quality = int(2**256 / 5 / estimate_st_performance())
 | 
				
			||||||
        self.mine_contract.set_quality(quality)
 | 
					        self.mine_contract.set_quality(quality)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SECTORS_PER_PRICING = int(8 * ( 2 ** 30 ) / 256)
 | 
					        SECTORS_PER_PRICING = int(8 * ( 2 ** 30 ) / 256)
 | 
				
			||||||
@ -52,17 +55,22 @@ class MineTest(TestFramework):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.log.info("Submit the data hash only (8 GB)")
 | 
					        self.log.info("Submit the data hash only (8 GB)")
 | 
				
			||||||
        self.submit_data(b"\x11", int(SECTORS_PER_PRICING), no_submit=True)
 | 
					        self.submit_data(b"\x11", int(SECTORS_PER_PRICING), no_submit=True)
 | 
				
			||||||
 | 
					        # wait_until(lambda: self.contract.epoch() >= 1, timeout=180)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        start_epoch = self.contract.epoch()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        self.log.info("Submission Done, epoch is %d, current block number %d", start_epoch, int(blockchain.eth_blockNumber(), 16))  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Sumission Done, Current block number %d", int(blockchain.eth_blockNumber(), 16))
 | 
					 | 
				
			||||||
        self.log.info("Wait for mine context release")
 | 
					        self.log.info("Wait for mine context release")
 | 
				
			||||||
        wait_until(lambda: self.contract.get_mine_context()[0] > 0, timeout=180)
 | 
					        wait_until(lambda: self.contract.epoch() >= start_epoch + 1, timeout=180)
 | 
				
			||||||
        self.log.info("Current flow length: %d", self.contract.get_mine_context()[3])
 | 
					        self.log.info("Current flow length: %d", self.contract.get_mine_context()[3])
 | 
				
			||||||
 | 
					        self.contract.update_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Wait for mine answer")
 | 
					        self.log.info("Wait for mine answer")
 | 
				
			||||||
        wait_until(lambda: self.mine_contract.last_mined_epoch() == 1)
 | 
					        wait_until(lambda: self.mine_contract.last_mined_epoch() == start_epoch + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        rewards = self.reward_contract.reward_distributes()
 | 
					        rewards = self.reward_contract.reward_distributes()
 | 
				
			||||||
        assert_equal(len(self.reward_contract.reward_distributes()), 1)
 | 
					        assert_equal(len(self.reward_contract.reward_distributes()), start_epoch + 1)
 | 
				
			||||||
        firstReward = rewards[0].args.amount
 | 
					        firstReward = rewards[0].args.amount
 | 
				
			||||||
        self.log.info("Received reward %d Gwei", firstReward / (10**9))
 | 
					        self.log.info("Received reward %d Gwei", firstReward / (10**9))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -70,22 +78,25 @@ class MineTest(TestFramework):
 | 
				
			|||||||
        self.log.info("Donation Done")
 | 
					        self.log.info("Donation Done")
 | 
				
			||||||
        self.log.info("Submit the data hash only (8 GB)")
 | 
					        self.log.info("Submit the data hash only (8 GB)")
 | 
				
			||||||
        self.submit_data(b"\x11", int(SECTORS_PER_PRICING), no_submit=True)
 | 
					        self.submit_data(b"\x11", int(SECTORS_PER_PRICING), no_submit=True)
 | 
				
			||||||
        self.log.info("Sumission Done, Current block number %d", int(blockchain.eth_blockNumber(), 16))
 | 
					        current_epoch = self.contract.epoch()
 | 
				
			||||||
 | 
					        assert_equal(current_epoch, start_epoch + 1);
 | 
				
			||||||
 | 
					        self.log.info("Sumission Done, epoch is %d, current block number %d", self.contract.epoch(), int(blockchain.eth_blockNumber(), 16))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        self.log.info("Wait for mine context release")
 | 
					        self.log.info("Wait for mine context release")
 | 
				
			||||||
        wait_until(lambda: self.contract.get_mine_context()[0] > 1, timeout=180)
 | 
					        wait_until(lambda: self.contract.epoch() >= start_epoch + 2, timeout=180)
 | 
				
			||||||
 | 
					        self.contract.update_context()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.log.info("Wait for mine answer")
 | 
					        self.log.info("Wait for mine answer")
 | 
				
			||||||
        wait_until(lambda: self.mine_contract.last_mined_epoch() == 2)
 | 
					        wait_until(lambda: self.mine_contract.last_mined_epoch() == start_epoch + 2)
 | 
				
			||||||
        rewards = self.reward_contract.reward_distributes()
 | 
					        rewards = self.reward_contract.reward_distributes()
 | 
				
			||||||
        assert_equal(len(self.reward_contract.reward_distributes()), 2)
 | 
					        assert_equal(len(self.reward_contract.reward_distributes()), start_epoch + 2)
 | 
				
			||||||
        secondReward = rewards[1].args.amount
 | 
					        secondReward = rewards[1].args.amount
 | 
				
			||||||
        self.log.info("Received reward %d Gwei", secondReward / (10**9))
 | 
					        self.log.info("Received reward %d Gwei", secondReward / (10**9))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_greater_than(secondReward, 100 * firstReward)
 | 
					        assert_greater_than(secondReward, 100 * firstReward / (start_epoch + 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    MineTest().main()
 | 
					    MineTest(blockchain_node_type=BlockChainNodeType.BSC).main()
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@ from utility.simple_rpc_proxy import SimpleRpcProxy
 | 
				
			|||||||
from utility.utils import (
 | 
					from utility.utils import (
 | 
				
			||||||
    initialize_config,
 | 
					    initialize_config,
 | 
				
			||||||
    wait_until,
 | 
					    wait_until,
 | 
				
			||||||
 | 
					    estimate_st_performance
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from test_framework.contracts import load_contract_metadata
 | 
					from test_framework.contracts import load_contract_metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -32,7 +33,7 @@ class BlockChainNodeType(Enum):
 | 
				
			|||||||
        if self == BlockChainNodeType.Conflux:
 | 
					        if self == BlockChainNodeType.Conflux:
 | 
				
			||||||
            return 0.5
 | 
					            return 0.5
 | 
				
			||||||
        elif self == BlockChainNodeType.BSC:
 | 
					        elif self == BlockChainNodeType.BSC:
 | 
				
			||||||
            return 0.25
 | 
					            return 25 / estimate_st_performance()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return 3.0
 | 
					            return 3.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ class ContractProxy:
 | 
				
			|||||||
        assert node_idx < len(self.blockchain_nodes)
 | 
					        assert node_idx < len(self.blockchain_nodes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        contract = self._get_contract(node_idx)
 | 
					        contract = self._get_contract(node_idx)
 | 
				
			||||||
        return getattr(contract.functions, fn_name)(**args).transact(TX_PARAMS)
 | 
					        return getattr(contract.functions, fn_name)(**args).transact(copy(TX_PARAMS))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    def _logs(self, event_name, node_idx, **args):
 | 
					    def _logs(self, event_name, node_idx, **args):
 | 
				
			||||||
        assert node_idx < len(self.blockchain_nodes)
 | 
					        assert node_idx < len(self.blockchain_nodes)
 | 
				
			||||||
@ -37,7 +37,7 @@ class ContractProxy:
 | 
				
			|||||||
        return getattr(contract.events, event_name).create_filter(fromBlock =0, toBlock="latest").get_all_entries()
 | 
					        return getattr(contract.events, event_name).create_filter(fromBlock =0, toBlock="latest").get_all_entries()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def transfer(self, value, node_idx = 0):
 | 
					    def transfer(self, value, node_idx = 0):
 | 
				
			||||||
        tx_params = TX_PARAMS
 | 
					        tx_params = copy(TX_PARAMS)
 | 
				
			||||||
        tx_params["value"] = value
 | 
					        tx_params["value"] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        contract = self._get_contract(node_idx)
 | 
					        contract = self._get_contract(node_idx)
 | 
				
			||||||
@ -53,7 +53,7 @@ class FlowContractProxy(ContractProxy):
 | 
				
			|||||||
    ):
 | 
					    ):
 | 
				
			||||||
        assert node_idx < len(self.blockchain_nodes)
 | 
					        assert node_idx < len(self.blockchain_nodes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        combined_tx_prarams = TX_PARAMS
 | 
					        combined_tx_prarams = copy(TX_PARAMS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if tx_prarams is not None:
 | 
					        if tx_prarams is not None:
 | 
				
			||||||
            combined_tx_prarams.update(tx_prarams)
 | 
					            combined_tx_prarams.update(tx_prarams)
 | 
				
			||||||
@ -77,7 +77,10 @@ class FlowContractProxy(ContractProxy):
 | 
				
			|||||||
        return self._call("firstBlock", node_idx)
 | 
					        return self._call("firstBlock", node_idx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def epoch(self, node_idx=0):
 | 
					    def epoch(self, node_idx=0):
 | 
				
			||||||
        return self._call("epoch", node_idx)
 | 
					        return self.get_mine_context(node_idx)[0]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def update_context(self, node_idx=0):
 | 
				
			||||||
 | 
					        return self._send("makeContext", node_idx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_mine_context(self, node_idx=0):
 | 
					    def get_mine_context(self, node_idx=0):
 | 
				
			||||||
        return self._call("makeContextWithResult", node_idx)
 | 
					        return self._call("makeContextWithResult", node_idx)
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ import os
 | 
				
			|||||||
import platform
 | 
					import platform
 | 
				
			||||||
import rtoml
 | 
					import rtoml
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					import sha3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from config.node_config import ZGS_CONFIG
 | 
					from config.node_config import ZGS_CONFIG
 | 
				
			||||||
from eth_utils import encode_hex
 | 
					from eth_utils import encode_hex
 | 
				
			||||||
@ -130,3 +131,12 @@ def assert_greater_than(thing1, thing2):
 | 
				
			|||||||
def assert_greater_than_or_equal(thing1, thing2):
 | 
					def assert_greater_than_or_equal(thing1, thing2):
 | 
				
			||||||
    if thing1 < thing2:
 | 
					    if thing1 < thing2:
 | 
				
			||||||
        raise AssertionError("%s < %s" % (str(thing1), str(thing2)))
 | 
					        raise AssertionError("%s < %s" % (str(thing1), str(thing2)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 14900K has the performance point 100 
 | 
				
			||||||
 | 
					def estimate_st_performance():
 | 
				
			||||||
 | 
					    hasher = sha3.keccak_256()
 | 
				
			||||||
 | 
					    input =  b"\xcc" * (1<<26)
 | 
				
			||||||
 | 
					    start_time = time.perf_counter()
 | 
				
			||||||
 | 
					    hasher.update(input)
 | 
				
			||||||
 | 
					    digest = hasher.hexdigest()
 | 
				
			||||||
 | 
					    return 10 / (time.perf_counter() - start_time)
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user