use super::codec::{Header, Id, U256};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Tip {
pub height: u64,
pub id: Id,
pub chainwork: U256,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum HeaderVerdict {
Accepted,
Known,
Orphan,
Held,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum HeaderError {
Syntax(String),
WrongChain,
BadBits,
BadParent,
BadTime,
BadTarget,
BadPow,
InvalidParent,
UnknownRuleSet,
Refused(String),
Store(String),
}
impl HeaderError {
pub fn score(&self) -> u32 {
match self {
HeaderError::BadPow | HeaderError::WrongChain => 100,
HeaderError::Syntax(_) | HeaderError::BadBits | HeaderError::BadTime | HeaderError::BadTarget => 10,
HeaderError::BadParent | HeaderError::InvalidParent | HeaderError::UnknownRuleSet => 10,
HeaderError::Refused(_) | HeaderError::Store(_) => 0,
}
}
}
impl std::fmt::Display for HeaderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HeaderError::Syntax(s) => write!(f, "syntax: {s}"),
HeaderError::Refused(s) => write!(f, "refused: {s}"),
HeaderError::Store(s) => write!(f, "store: {s}"),
other => write!(f, "{other:?}"),
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum BlockVerdict {
NewTip,
Stored,
Known,
NeedBodies(Vec<Id>),
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum BlockError {
UnknownParent,
Header(HeaderError),
Held,
Refused(String),
Invalid(String),
Store(String),
}
impl BlockError {
pub fn score(&self) -> u32 {
match self {
BlockError::Header(e) => e.score(),
BlockError::Invalid(_) => 10,
BlockError::UnknownParent | BlockError::Held | BlockError::Refused(_) | BlockError::Store(_) => 0,
}
}
}
impl std::fmt::Display for BlockError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BlockError::UnknownParent => write!(f, "unknown parent"),
BlockError::Header(e) => write!(f, "header: {e}"),
BlockError::Held => write!(f, "ahead of the clock; held"),
BlockError::Refused(s) => write!(f, "refused: {s}"),
BlockError::Invalid(s) => write!(f, "invalid: {s}"),
BlockError::Store(s) => write!(f, "store: {s}"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Admitted {
pub txid: Id,
pub account: Id,
pub nonce: u64,
pub fee: u64,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TxRefusal {
Decode(String),
Kind,
Signature,
Nonce { current: u64, got: u64 },
Fee { floor: u64, got: u64 },
Balance(String),
Rule(String),
}
#[derive(Clone, Debug)]
pub enum ChainEvent {
NewTip { height: u64, id: Id, reorged_out: Vec<Vec<u8>> },
}
pub trait ChainView: Send + Sync + 'static {
fn chain_id(&self) -> Id;
fn genesis_id(&self) -> Id;
fn chain_name(&self) -> String;
fn hrp(&self) -> String;
fn rule_set(&self) -> u16 {
super::codec::RULE_SET
}
fn native_token(&self) -> Id;
fn subsidy(&self) -> u64;
fn genesis_time(&self) -> u64;
fn checkpoint_key(&self) -> Option<[u8; 33]>;
fn tip(&self) -> Tip;
fn best_header(&self) -> Tip;
fn header(&self, id: &Id) -> Option<Header>;
fn header_at(&self, height: u64) -> Option<Header>;
fn chainwork_of(&self, id: &Id) -> Option<U256>;
fn has_body(&self, id: &Id) -> bool;
fn block(&self, id: &Id) -> Option<(Header, Vec<u8>)>;
fn block_at(&self, height: u64) -> Option<(Header, Vec<u8>)>;
fn height_of(&self, id: &Id) -> Option<u64>;
fn locator(&self) -> Vec<Id>;
fn headers_from_locator(&self, locator: &[Id], stop: &Id, max: usize) -> Vec<Header>;
fn accept_header(&self, header: &Header, now: u64) -> Result<HeaderVerdict, HeaderError>;
fn accept_block(&self, header: &Header, body: &[u8], now: u64) -> Result<BlockVerdict, BlockError>;
fn retry_held(&self, now: u64) -> Vec<Header>;
fn accept_checkpoint(&self, height: u64, block_id: &Id, sig: &[u8]) -> Result<bool, String>;
fn missing_bodies(&self, max: usize) -> Vec<(u64, Id)>;
fn nonce(&self, neuron: &Id) -> u64;
fn validate_tx(&self, tx: &[u8], pending: &[Vec<u8>]) -> Result<Admitted, TxRefusal>;
fn validate_run(&self, txs: &[Vec<u8>]) -> Vec<Result<Admitted, TxRefusal>> {
(0..txs.len()).map(|i| self.validate_tx(&txs[i], &txs[..i])).collect()
}
fn balance(&self, owner: &Id, token: &Id) -> u64;
fn spendable(&self, owner: &Id, token: &Id) -> u64;
fn balances(&self, owner: &Id) -> Vec<(Id, u64)>;
fn tx_location(&self, txid: &Id) -> Option<(u64, Id, u32)>;
fn supply(&self, token: &Id) -> u64;
fn conserved(&self) -> bool;
fn counts(&self) -> (u64, u64, u64);
fn state_root(&self) -> Id;
fn template(&self, to: &Id, txs: &[Vec<u8>], now: u64) -> Result<(Header, Vec<u8>), String>;
fn template_json(&self, header: &Header, body: &[u8], expires: u64) -> String;
fn events(&self) -> tokio::sync::broadcast::Receiver<ChainEvent>;
fn txs_of(&self, body: &[u8]) -> Vec<Vec<u8>> {
super::codec::decode_body(body).unwrap_or_default()
}
}