#![forbid(unsafe_code)]
#![deny(missing_docs)]
#[doc(inline)]
pub use block::{Block, Header as BlockHeader};
use essential_types::{
contract::Contract,
convert::{word_4_from_u8_32, word_from_bytes_slice},
predicate::{PredicateEncodeError, Program},
solution::{Mutation, Solution, SolutionSet},
PredicateAddress, Word,
};
use serde::{Deserialize, Serialize};
pub mod block;
#[cfg(feature = "block-notify")]
pub mod block_notify;
pub const DEFAULT_BIG_BANG: &str = include_str!("../big-bang.yml");
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Ord, Serialize, Deserialize)]
pub struct BigBang {
pub block_state: PredicateAddress,
pub contract_registry: PredicateAddress,
pub program_registry: PredicateAddress,
pub solution_set: SolutionSet,
}
impl BigBang {
pub fn block(&self) -> Block {
Block {
header: BlockHeader {
number: 0,
timestamp: std::time::Duration::from_secs(0),
},
solution_sets: vec![self.solution_set.clone()],
}
}
}
impl Default for BigBang {
fn default() -> Self {
serde_yaml::from_str(DEFAULT_BIG_BANG)
.expect("default `big-bang-block.yml` must be valid (checked in tests)")
}
}
pub mod contract_registry {
use crate::padded_words_from_bytes;
use essential_types::{ContentAddress, Key, PredicateAddress, Word};
const CONTRACTS_PREFIX: Word = 0;
const PREDICATES_PREFIX: Word = 1;
pub fn contract_salt_key(contract_ca: &ContentAddress) -> Key {
Some(CONTRACTS_PREFIX)
.into_iter()
.chain(padded_words_from_bytes(&contract_ca.0))
.chain(Some(0))
.collect()
}
pub fn contract_predicate_key(pred_addr: &PredicateAddress) -> Key {
Some(CONTRACTS_PREFIX)
.into_iter()
.chain(padded_words_from_bytes(&pred_addr.contract.0))
.chain(padded_words_from_bytes(&pred_addr.predicate.0))
.collect()
}
pub fn predicate_key(pred_ca: &ContentAddress) -> Key {
Some(PREDICATES_PREFIX)
.into_iter()
.chain(padded_words_from_bytes(&pred_ca.0))
.collect()
}
}
pub mod program_registry {
use crate::padded_words_from_bytes;
use essential_types::{ContentAddress, Key, Word};
const PROGRAMS_PREFIX: Word = 0;
pub fn program_key(prog_ca: &ContentAddress) -> Key {
Some(PROGRAMS_PREFIX)
.into_iter()
.chain(padded_words_from_bytes(&prog_ca.0))
.collect()
}
}
pub fn register_contract_solution(
contract_registry: PredicateAddress,
contract: &Contract,
) -> Result<Solution, PredicateEncodeError> {
Ok(Solution {
predicate_to_solve: contract_registry,
predicate_data: vec![],
state_mutations: register_contract_mutations(contract)?,
})
}
pub fn register_contract_mutations(
contract: &Contract,
) -> Result<Vec<Mutation>, PredicateEncodeError> {
let mut muts = vec![];
let contract_ca = essential_hash::content_addr(contract);
let salt_w = word_4_from_u8_32(contract.salt);
muts.push(Mutation {
key: contract_registry::contract_salt_key(&contract_ca),
value: salt_w.to_vec(),
});
for pred in &contract.predicates {
let pred_ca = essential_hash::content_addr(pred);
let pred_addr = PredicateAddress {
contract: contract_ca.clone(),
predicate: pred_ca,
};
let key = contract_registry::contract_predicate_key(&pred_addr);
muts.push(Mutation {
key,
value: vec![1],
});
let pred_bytes: Vec<u8> = pred.encode()?.collect();
let len_bytes = pred_bytes.len();
let len_bytes_w = Word::try_from(len_bytes).expect("checked during `encode`");
let key = contract_registry::predicate_key(&pred_addr.predicate);
muts.push(Mutation {
key,
value: Some(len_bytes_w)
.into_iter()
.chain(padded_words_from_bytes(&pred_bytes))
.collect(),
});
}
Ok(muts)
}
pub fn register_program_solution(
program_registry: PredicateAddress,
program: &Program,
) -> Solution {
Solution {
predicate_to_solve: program_registry,
predicate_data: vec![],
state_mutations: register_program_mutations(program),
}
}
pub fn register_program_mutations(program: &Program) -> Vec<Mutation> {
let mut muts = vec![];
let prog_ca = essential_hash::content_addr(program);
let prog_bytes = &program.0;
let len_bytes = prog_bytes.len();
let len_bytes_w = Word::try_from(len_bytes).expect("should be enforced by Program::MAX_SIZE");
let key = program_registry::program_key(&prog_ca);
muts.push(Mutation {
key,
value: Some(len_bytes_w)
.into_iter()
.chain(padded_words_from_bytes(prog_bytes))
.collect(),
});
muts
}
pub fn block_state_solution(
block_state: PredicateAddress,
block_number: Word,
block_timestamp_secs: Word,
) -> Solution {
Solution {
predicate_to_solve: block_state,
predicate_data: vec![],
state_mutations: block_state_mutations(block_number, block_timestamp_secs),
}
}
pub fn block_state_mutations(block_number: Word, block_timestamp_secs: Word) -> Vec<Mutation> {
vec![
Mutation {
key: vec![0],
value: vec![block_number],
},
Mutation {
key: vec![1],
value: vec![block_timestamp_secs],
},
]
}
fn padded_words_from_bytes(bytes: &[u8]) -> impl '_ + Iterator<Item = Word> {
bytes
.chunks(core::mem::size_of::<Word>())
.map(word_from_bytes_slice)
}