mod http_server;
use linera_base::{
crypto::{AccountPublicKey, Signer, ValidatorPublicKey},
data_types::{Amount, BlockHeight, Epoch, Round, Timestamp},
identifiers::{Account, AccountOwner, ChainId},
};
use linera_execution::{
committee::{Committee, ValidatorState},
Message, MessageKind, Operation, ResourceControlPolicy, SystemOperation,
};
pub use self::http_server::HttpServer;
use crate::{
block::ConfirmedBlock,
data_types::{
BlockProposal, IncomingBundle, PostedMessage, ProposedBlock, SignatureAggregator,
Transaction, Vote,
},
types::{CertificateValue, GenericCertificate},
};
pub fn make_child_block(parent: &ConfirmedBlock) -> ProposedBlock {
let parent_header = &parent.block().header;
ProposedBlock {
epoch: parent_header.epoch,
chain_id: parent_header.chain_id,
transactions: vec![],
previous_block_hash: Some(parent.hash()),
height: parent_header.height.try_add_one().unwrap(),
authenticated_signer: parent_header.authenticated_signer,
timestamp: parent_header.timestamp,
}
}
pub fn make_first_block(chain_id: ChainId) -> ProposedBlock {
ProposedBlock {
epoch: Epoch::ZERO,
chain_id,
transactions: vec![],
previous_block_hash: None,
height: BlockHeight::ZERO,
authenticated_signer: None,
timestamp: Timestamp::default(),
}
}
#[allow(async_fn_in_trait)]
pub trait BlockTestExt: Sized {
fn with_authenticated_signer(self, authenticated_signer: Option<AccountOwner>) -> Self;
fn with_operation(self, operation: impl Into<Operation>) -> Self;
fn with_transfer(self, owner: AccountOwner, recipient: Account, amount: Amount) -> Self;
fn with_simple_transfer(self, chain_id: ChainId, amount: Amount) -> Self;
fn with_incoming_bundle(self, incoming_bundle: IncomingBundle) -> Self;
fn with_timestamp(self, timestamp: impl Into<Timestamp>) -> Self;
fn with_epoch(self, epoch: impl Into<Epoch>) -> Self;
fn with_burn(self, amount: Amount) -> Self;
async fn into_first_proposal<S: Signer + ?Sized>(
self,
owner: AccountOwner,
signer: &S,
) -> Result<BlockProposal, S::Error> {
self.into_proposal_with_round(owner, signer, Round::MultiLeader(0))
.await
}
async fn into_proposal_with_round<S: Signer + ?Sized>(
self,
owner: AccountOwner,
signer: &S,
round: Round,
) -> Result<BlockProposal, S::Error>;
}
impl BlockTestExt for ProposedBlock {
fn with_authenticated_signer(mut self, authenticated_signer: Option<AccountOwner>) -> Self {
self.authenticated_signer = authenticated_signer;
self
}
fn with_operation(mut self, operation: impl Into<Operation>) -> Self {
self.transactions
.push(Transaction::ExecuteOperation(operation.into()));
self
}
fn with_transfer(self, owner: AccountOwner, recipient: Account, amount: Amount) -> Self {
self.with_operation(SystemOperation::Transfer {
owner,
recipient,
amount,
})
}
fn with_simple_transfer(self, chain_id: ChainId, amount: Amount) -> Self {
self.with_transfer(AccountOwner::CHAIN, Account::chain(chain_id), amount)
}
fn with_burn(self, amount: Amount) -> Self {
let recipient = Account::burn_address(self.chain_id);
self.with_operation(SystemOperation::Transfer {
owner: AccountOwner::CHAIN,
recipient,
amount,
})
}
fn with_incoming_bundle(mut self, incoming_bundle: IncomingBundle) -> Self {
self.transactions
.push(Transaction::ReceiveMessages(incoming_bundle));
self
}
fn with_timestamp(mut self, timestamp: impl Into<Timestamp>) -> Self {
self.timestamp = timestamp.into();
self
}
fn with_epoch(mut self, epoch: impl Into<Epoch>) -> Self {
self.epoch = epoch.into();
self
}
async fn into_proposal_with_round<S: Signer + ?Sized>(
self,
owner: AccountOwner,
signer: &S,
round: Round,
) -> Result<BlockProposal, S::Error> {
BlockProposal::new_initial(owner, round, self, signer).await
}
}
pub trait VoteTestExt<T: CertificateValue>: Sized {
fn into_certificate(self, public_key: ValidatorPublicKey) -> GenericCertificate<T>;
}
impl<T: CertificateValue> VoteTestExt<T> for Vote<T> {
fn into_certificate(self, public_key: ValidatorPublicKey) -> GenericCertificate<T> {
let state = ValidatorState {
network_address: "".to_string(),
votes: 100,
account_public_key: AccountPublicKey::test_key(1),
};
let committee = Committee::new(
vec![(public_key, state)].into_iter().collect(),
ResourceControlPolicy::only_fuel(),
);
SignatureAggregator::new(self.value, self.round, &committee)
.append(public_key, self.signature)
.unwrap()
.unwrap()
}
}
pub trait MessageTestExt: Sized {
fn to_posted(self, index: u32, kind: MessageKind) -> PostedMessage;
}
impl<T: Into<Message>> MessageTestExt for T {
fn to_posted(self, index: u32, kind: MessageKind) -> PostedMessage {
PostedMessage {
authenticated_signer: None,
grant: Amount::ZERO,
refund_grant_to: None,
kind,
index,
message: self.into(),
}
}
}