use std::{
collections::BTreeMap,
sync::Arc,
};
use account_state::state::StateInfo;
use blockchain::BlockProvider;
use bytes::Bytes;
use call_contract::CallContract;
use tetsy_registrar::RegistrarClient;
use common_types::{
basic_account::BasicAccount,
block_status::BlockStatus,
blockchain_info::BlockChainInfo,
BlockNumber,
call_analytics::CallAnalytics,
chain_notify::{NewBlocks, ChainMessageType},
client_types::Mode,
encoded,
engines::{epoch::Transition as EpochTransition, machine::Executed},
errors::{VapcoreError, VapcoreResult},
filter::Filter,
header::Header,
ids::{BlockId, TransactionId, TraceId, UncleId},
log_entry::LocalizedLogEntry,
pruning_info::PruningInfo,
receipt::LocalizedReceipt,
trace_filter::Filter as TraceFilter,
transaction::{self, Action, LocalizedTransaction, CallError, SignedTransaction, UnverifiedTransaction},
tree_route::TreeRoute,
verification::{VerificationQueueInfo, Unverified},
};
use vapory_types::{Address, H256, U256};
use vapcore_db::keys::BlockReceipts;
use vapcore_miner::pool::VerifiedTransaction;
use tetsy_kvdb::DBValue;
use tetsy_stats;
use vapcore_trace::{
FlatTrace,
localized::LocalizedTrace,
VMTrace,
};
use common_types::{
data_format::DataFormat,
client_types::StateResult
};
use tetsy_vm::{LastHashes, Schedule};
pub enum StateOrBlock {
State(Box<dyn StateInfo>),
Block(BlockId)
}
impl From<Box<dyn StateInfo>> for StateOrBlock {
fn from(info: Box<dyn StateInfo>) -> StateOrBlock {
StateOrBlock::State(info)
}
}
impl From<BlockId> for StateOrBlock {
fn from(id: BlockId) -> StateOrBlock {
StateOrBlock::Block(id)
}
}
pub trait Nonce {
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256>;
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockId::Latest)
.expect("nonce will return Some when given BlockId::Latest. nonce was given BlockId::Latest. \
Therefore nonce has returned Some; qed")
}
}
pub trait Balance {
fn balance(&self, address: &Address, state: StateOrBlock) -> Option<U256>;
fn latest_balance(&self, address: &Address) -> U256 {
self.balance(address, BlockId::Latest.into())
.expect("balance will return Some if given BlockId::Latest. balance was given BlockId::Latest \
Therefore balance has returned Some; qed")
}
}
pub trait AccountData: Nonce + Balance {}
pub trait ChainInfo {
fn chain_info(&self) -> BlockChainInfo;
}
pub trait BlockInfo: Send + Sync {
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
fn best_block_header(&self) -> Header;
fn block(&self, id: BlockId) -> Option<encoded::Block>;
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256>;
}
pub trait TransactionInfo {
fn transaction_block(&self, id: TransactionId) -> Option<H256>;
}
pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ForceUpdateSealing {
Yes,
No
}
pub trait EngineClient: Sync + Send + ChainInfo {
fn update_sealing(&self, force: ForceUpdateSealing);
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>);
fn broadcast_consensus_message(&self, message: Bytes);
fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition>;
fn as_full_client(&self) -> Option<&dyn BlockChainClient>;
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
}
pub trait ImportBlock {
fn import_block(&self, block: Unverified) -> VapcoreResult<H256>;
fn import_verified_blocks(&self) -> usize;
}
pub trait IoClient: Sync + Send {
fn queue_transactions(&self, transactions: Vec<Bytes>, peer_id: usize);
fn queue_ancient_block(&self, block_bytes: Unverified, receipts_bytes: Bytes) -> VapcoreResult<H256>;
fn queue_consensus_message(&self, message: Bytes);
}
pub trait Tick {
fn tick(&self, _prevent_sleep: bool) {}
}
impl Tick for () {}
pub trait BadBlocks {
fn bad_blocks(&self) -> Vec<(Unverified, String)>;
}
pub trait BlockChainClient:
Sync + Send + AccountData + BlockChain + CallContract + RegistrarClient
+ ImportBlock + IoClient + BadBlocks
{
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
fn block_status(&self, id: BlockId) -> BlockStatus;
fn block_total_difficulty(&self, id: BlockId) -> Option<U256>;
fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256>;
fn block_hash(&self, id: BlockId) -> Option<H256>;
fn code(&self, address: &Address, state: StateOrBlock) -> StateResult<Option<Bytes>>;
fn latest_code(&self, address: &Address) -> Option<Bytes> {
match self.code(address, BlockId::Latest.into()) {
StateResult::Missing => panic!("code will return Some if given BlockId::Latest; qed"),
StateResult::Some(t) => t,
}
}
fn chain(&self) -> Arc<dyn BlockProvider>;
fn queue_info(&self) -> VerificationQueueInfo;
fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option<H256>;
fn latest_storage_at(&self, address: &Address, position: &H256) -> H256 {
self.storage_at(address, position, BlockId::Latest.into())
.expect("storage_at will return Some if given BlockId::Latest. storage_at was given BlockId::Latest. \
Therefore storage_at has returned Some; qed")
}
fn list_accounts(&self, id: BlockId, after: Option<&Address>, count: u64) -> Option<Vec<Address>>;
fn list_storage(&self, id: BlockId, account: &Address, after: Option<&H256>, count: Option<u64>) -> Option<Vec<H256>>;
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;
fn uncle(&self, id: UncleId) -> Option<encoded::Header>;
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>;
fn localized_block_receipts(&self, id: BlockId) -> Option<Vec<LocalizedReceipt>>;
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
fn find_uncles(&self, hash: &H256) -> Option<Vec<H256>>;
fn state_data(&self, hash: &H256) -> Option<Bytes>;
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;
fn is_queue_empty(&self) -> bool {
self.queue_info().is_empty()
}
fn clear_queue(&self);
fn logs(&self, filter: Filter) -> Result<Vec<LocalizedLogEntry>, BlockId>;
fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed<FlatTrace, VMTrace>, CallError>;
fn replay_block_transactions(&self, block: BlockId, analytics: CallAnalytics) -> Result<Box<dyn Iterator<Item = (H256, Executed<FlatTrace, VMTrace>)>>, CallError>;
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>>;
fn trace(&self, trace: TraceId) -> Option<LocalizedTrace>;
fn transaction_traces(&self, trace: TransactionId) -> Option<Vec<LocalizedTrace>>;
fn block_traces(&self, trace: BlockId) -> Option<Vec<LocalizedTrace>>;
fn last_hashes(&self) -> LastHashes;
fn transactions_to_propagate(&self) -> Vec<Arc<VerifiedTransaction>>;
fn gas_price_corpus(&self, sample_size: usize) -> tetsy_stats::Corpus<U256> {
let mut h = self.chain_info().best_block_hash;
let mut corpus = Vec::new();
while corpus.is_empty() {
for _ in 0..sample_size {
let block = match self.block(BlockId::Hash(h)) {
Some(block) => block,
None => return corpus.into(),
};
if block.number() == 0 {
return corpus.into();
}
for t in block.transaction_views().iter() {
corpus.push( t.gas_price() )
}
h = block.parent_hash().clone();
}
}
corpus.into()
}
fn signing_chain_id(&self) -> Option<u64>;
fn mode(&self) -> Mode;
fn set_mode(&self, mode: Mode);
fn spec_name(&self) -> String;
fn set_spec_name(&self, spec_name: String) -> Result<(), ()>;
fn disable(&self);
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>>;
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>>;
fn pruning_info(&self) -> PruningInfo;
fn create_transaction(&self, tx_request: TransactionRequest) -> Result<SignedTransaction, transaction::Error>;
fn transact(&self, tx_request: TransactionRequest) -> Result<(), transaction::Error>;
}
pub struct TransactionRequest {
pub action: Action,
pub data: Bytes,
pub gas: Option<U256>,
pub gas_price: Option<U256>,
pub nonce: Option<U256>,
}
impl TransactionRequest {
pub fn call(address: Address, data: Bytes) -> TransactionRequest {
TransactionRequest {
action: Action::Call(address),
data,
gas: None,
gas_price: None,
nonce: None,
}
}
pub fn create(data: Bytes) -> TransactionRequest {
TransactionRequest {
action: Action::Create,
data,
gas: None,
gas_price: None,
nonce: None,
}
}
pub fn gas(mut self, gas: U256) -> TransactionRequest {
self.gas = Some(gas);
self
}
pub fn gas_price(mut self, gas_price: U256) -> TransactionRequest {
self.gas_price = Some(gas_price);
self
}
pub fn nonce(mut self, nonce: U256) -> TransactionRequest {
self.nonce = Some(nonce);
self
}
}
pub trait BlockChainReset {
fn reset(&self, num: u32) -> Result<(), String>;
fn pruning_history(&self) -> u64;
}
pub trait ScheduleInfo {
fn latest_schedule(&self) -> Schedule;
}
pub trait StateClient {
type State: StateInfo;
fn latest_state_and_header(&self) -> (Self::State, Header);
fn state_at(&self, id: BlockId) -> Option<Self::State>;
}
pub trait ProvingBlockChainClient: BlockChainClient {
fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec<Bytes>, H256)>;
fn prove_account(&self, key1: H256, id: BlockId) -> Option<(Vec<Bytes>, BasicAccount)>;
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>;
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>>;
}
pub trait DatabaseRestore: Send + Sync {
fn restore_db(&self, new_db: &str) -> Result<(), VapcoreError>;
}
pub trait ChainNotify: Send + Sync {
fn new_blocks(&self, _new_blocks: NewBlocks) {
}
fn start(&self) {
}
fn stop(&self) {
}
fn broadcast(&self, _message_type: ChainMessageType) {
}
fn block_pre_import(&self, _bytes: &Bytes, _hash: &H256, _difficulty: &U256) {
}
fn transactions_received(&self, _txs: &[UnverifiedTransaction], _peer_id: usize) {
}
}
pub trait ImportExportBlocks {
fn export_blocks<'a>(
&self,
destination: Box<dyn std::io::Write + 'a>,
from: BlockId,
to: BlockId,
format: Option<DataFormat>
) -> Result<(), String>;
fn import_blocks<'a>(
&self,
source: Box<dyn std::io::Read + 'a>,
format: Option<DataFormat>
) -> Result<(), String>;
}