Skip to content

Commit

Permalink
feat(validator-node): committee proposes genesis block w/ instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Feb 17, 2022
1 parent 31410cd commit 919678b
Show file tree
Hide file tree
Showing 29 changed files with 513 additions and 530 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use tari_common_types::types::PublicKey;
use tari_comms::NodeIdentity;
use tari_crypto::tari_utilities::ByteArray;
use tari_dan_core::{
models::Instruction,
services::{AssetProcessor, AssetProxy, ServiceSpecification},
storage::DbFactory,
};
Expand Down Expand Up @@ -144,9 +145,10 @@ impl<TServiceSpecification: ServiceSpecification + 'static> rpc::validator_node_
.map_err(|e| Status::internal(format!("Could not create state db: {}", e)))?
{
let mut state_db_reader = state.reader();
let instruction = Instruction::new(template_id, request.method, request.args);
let response_bytes = self
.asset_processor
.invoke_read_method(template_id, request.method, &request.args, &mut state_db_reader)
.invoke_read_method(&instruction, &mut state_db_reader)
.map_err(|e| Status::internal(format!("Could not invoke read method: {}", e)))?;
Ok(Response::new(rpc::InvokeReadMethodResponse {
result: response_bytes.unwrap_or_default(),
Expand Down
25 changes: 16 additions & 9 deletions applications/tari_validator_node/src/p2p/rpc/service_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};

use log::*;
use tari_common_types::types::PublicKey;
Expand All @@ -30,7 +30,7 @@ use tari_comms::{
};
use tari_crypto::tari_utilities::ByteArray;
use tari_dan_core::{
models::{Instruction, TemplateId, TreeNodeHash},
models::{Instruction, TreeNodeHash},
services::{AssetProcessor, MempoolService},
storage::{state::StateDbUnitOfWorkReader, DbFactory},
};
Expand Down Expand Up @@ -93,14 +93,18 @@ where
.ok_or_else(|| RpcStatus::not_found("This node does not process this asset".to_string()))?;

let mut unit_of_work = state.reader();

let instruction = Instruction::new(
request
.template_id
.try_into()
.map_err(|_| RpcStatus::bad_request("Invalid template_id"))?,
request.method,
request.args,
);
let response_bytes = self
.asset_processor
.invoke_read_method(
TemplateId::try_from(request.template_id).map_err(|_| RpcStatus::bad_request("Invalid template_id"))?,
request.method,
&request.args,
&mut unit_of_work,
)
.invoke_read_method(&instruction, &mut unit_of_work)
.map_err(|e| RpcStatus::general(format!("Could not invoke read method: {}", e)))?;

Ok(Response::new(proto::InvokeReadMethodResponse {
Expand All @@ -115,7 +119,10 @@ where
dbg!(&request);
let request = request.into_message();
let instruction = Instruction::new(
TemplateId::try_from(request.template_id).map_err(|_| RpcStatus::bad_request("Invalid template_id"))?,
request
.template_id
.try_into()
.map_err(|_| RpcStatus::bad_request("Invalid template_id"))?,
request.method.clone(),
request.args.clone(),
/* TokenId(request.token_id.clone()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,10 @@ impl TariCommsInboundReceiverHandle {
}

#[async_trait]
impl InboundConnectionService<CommsPublicKey, TariDanPayload> for TariCommsInboundReceiverHandle {
impl InboundConnectionService for TariCommsInboundReceiverHandle {
type Addr = CommsPublicKey;
type Payload = TariDanPayload;

async fn wait_for_message(
&self,
message_type: HotStuffMessageType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ impl<TPayload: Payload> TariCommsOutboundService<TPayload> {
}

#[async_trait]
impl OutboundService<CommsPublicKey, TariDanPayload> for TariCommsOutboundService<TariDanPayload> {
impl OutboundService for TariCommsOutboundService<TariDanPayload> {
type Addr = CommsPublicKey;
type Payload = TariDanPayload;

async fn send(
&mut self,
from: CommsPublicKey,
Expand Down
8 changes: 8 additions & 0 deletions dan_layer/core/src/digital_assets_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ pub enum DigitalAssetError {
StateSyncError(#[from] StateSyncError),
#[error("Validator node client error: {0}")]
ValidatorNodeClientError(#[from] ValidatorNodeClientError),
#[error("Peer did not send a quorum certificate in prepare phase")]
PreparePhaseNoQuorumCertificate,
#[error("Quorum certificate does not extend node")]
PreparePhaseCertificateDoesNotExtendNode,
#[error("Node not safe")]
PreparePhaseNodeNotSafe,
#[error("Unsupported template method {name}")]
TemplateUnsupportedMethod { name: String },
}

impl From<lmdb_zero::Error> for DigitalAssetError {
Expand Down
2 changes: 1 addition & 1 deletion dan_layer/core/src/fixed_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const ZERO_HASH: [u8; FixedHash::byte_size()] = [0u8; FixedHash::byte_size()];
#[error("Invalid size")]
pub struct FixedHashSizeError;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
pub struct FixedHash([u8; FixedHash::byte_size()]);

impl FixedHash {
Expand Down
41 changes: 36 additions & 5 deletions dan_layer/core/src/models/instruction_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,37 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::{hash::Hash, iter::FromIterator};
use std::{convert::TryFrom, hash::Hash, iter::FromIterator};

use tari_crypto::common::Blake256;
use tari_mmr::MerkleMountainRange;

use crate::models::{ConsensusHash, Instruction};
use crate::{
fixed_hash::FixedHash,
models::{ConsensusHash, Instruction},
};

#[derive(PartialEq, Clone, Debug, Hash)]
pub struct InstructionSetHash(Vec<u8>);
pub struct InstructionSetHash(FixedHash);

impl InstructionSetHash {
pub fn zero() -> InstructionSetHash {
Self(FixedHash::zero())
}
}

impl InstructionSetHash {
pub fn as_bytes(&self) -> &[u8] {
self.0.as_slice()
}
}

impl From<FixedHash> for InstructionSetHash {
fn from(hash: FixedHash) -> Self {
Self(hash)
}
}

// TODO: Implement hash properly
#[allow(clippy::derive_hash_xor_eq)]
#[derive(Clone, Debug)]
Expand All @@ -52,7 +67,7 @@ impl InstructionSet {
pub fn from_vec(instructions: Vec<Instruction>) -> Self {
let mut result = Self {
instructions,
hash: InstructionSetHash(vec![]),
hash: InstructionSetHash::zero(),
};
result.hash = result.calculate_hash();
result
Expand All @@ -65,7 +80,7 @@ impl InstructionSet {
mmr.push(instruction.calculate_hash().to_vec()).unwrap();
}

InstructionSetHash(mmr.get_merkle_root().unwrap())
FixedHash::try_from(mmr.get_merkle_root().unwrap()).unwrap().into()
}

pub fn instructions(&self) -> &[Instruction] {
Expand All @@ -91,3 +106,19 @@ impl ConsensusHash for InstructionSet {
self.hash.as_bytes()
}
}

impl IntoIterator for InstructionSet {
type IntoIter = <Vec<Instruction> as IntoIterator>::IntoIter;
type Item = Instruction;

fn into_iter(self) -> Self::IntoIter {
self.instructions.into_iter()
}
}

impl Extend<Instruction> for InstructionSet {
fn extend<T: IntoIterator<Item = Instruction>>(&mut self, iter: T) {
self.instructions.extend(iter);
self.hash = self.calculate_hash();
}
}
4 changes: 4 additions & 0 deletions dan_layer/core/src/models/view_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ impl ViewId {
(self.0 % committee_size as u64) as usize
}

pub fn is_genesis(&self) -> bool {
self.0 == 0
}

pub fn next(&self) -> ViewId {
ViewId(self.0 + 1)
}
Expand Down
134 changes: 46 additions & 88 deletions dan_layer/core/src/services/asset_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,13 @@ use tari_core::transactions::transaction_components::TemplateParameter;

use crate::{
digital_assets_error::DigitalAssetError,
models::{AssetDefinition, Instruction, TemplateId},
models::{Instruction, InstructionSet, TemplateId},
storage::state::{StateDbUnitOfWork, StateDbUnitOfWorkReader},
template_command::ExecutionResult,
templates::{tip002_template, tip004_template, tip721_template},
};

pub trait AssetProcessor: Sync + Send + 'static {
fn init_template<TUnitOfWork: StateDbUnitOfWork>(
&self,
template_parameter: &TemplateParameter,
asset_definition: &AssetDefinition,
state_db: &mut TUnitOfWork,
) -> Result<(), DigitalAssetError>;

// purposefully made sync, because instructions should be run in order, and complete before the
// next one starts. There may be a better way to enforce this though...
fn execute_instruction<TUnitOfWork: StateDbUnitOfWork>(
Expand All @@ -50,10 +43,8 @@ pub trait AssetProcessor: Sync + Send + 'static {

fn invoke_read_method<TUnitOfWorkReader: StateDbUnitOfWorkReader>(
&self,
template_id: TemplateId,
method: String,
args: &[u8],
state_db: &mut TUnitOfWorkReader,
instruction: &Instruction,
state_db: &TUnitOfWorkReader,
) -> Result<Option<Vec<u8>>, DigitalAssetError>;
}

Expand All @@ -63,108 +54,75 @@ pub struct ConcreteAssetProcessor {
}

impl AssetProcessor for ConcreteAssetProcessor {
fn init_template<TUnitOfWork: StateDbUnitOfWork>(
&self,
template_parameter: &TemplateParameter,
asset_definition: &AssetDefinition,
state_db: &mut TUnitOfWork,
) -> Result<(), DigitalAssetError> {
self.template_factory
.init(template_parameter, asset_definition, state_db)
}

fn execute_instruction<TUnitOfWork: StateDbUnitOfWork>(
&self,
instruction: &Instruction,
db: &mut TUnitOfWork,
state_db: &mut TUnitOfWork,
) -> Result<(), DigitalAssetError> {
self.execute(
instruction.template_id(),
instruction.method().to_owned(),
instruction.args().into(),
// InstructionCaller {
// owner_token_id: instruction.from_owner().to_owned(),
// },
db,
)
self.template_factory.invoke_write_method(instruction, state_db)
}

fn invoke_read_method<TUnitOfWork: StateDbUnitOfWorkReader>(
&self,
template_id: TemplateId,
method: String,
args: &[u8],
state_db: &mut TUnitOfWork,
instruction: &Instruction,
state_db: &TUnitOfWork,
) -> Result<Option<Vec<u8>>, DigitalAssetError> {
self.template_factory.invoke_read_method(instruction, state_db)
}
}

#[derive(Default, Clone)]
pub struct TemplateFactory {}

impl TemplateFactory {
pub fn initial_instructions(&self, template_param: &TemplateParameter) -> InstructionSet {
use TemplateId::*;
// TODO: We may want to use the TemplateId type, so that we know it is known/valid
let template_id = template_param.template_id.try_into().unwrap();
match template_id {
TemplateId::Tip002 => tip002_template::invoke_read_method(method, args, state_db),
TemplateId::Tip004 => tip004_template::invoke_read_method(method, args, state_db),
TemplateId::Tip721 => tip721_template::invoke_read_method(method, args, state_db),
_ => {
Tip002 => tip002_template::initial_instructions(template_param),
Tip003 => todo!(),
Tip004 => tip004_template::initial_instructions(template_param),
Tip721 => tip721_template::initial_instructions(template_param),
EditableMetadata => {
todo!()
},
}
}
}

impl ConcreteAssetProcessor {
pub fn execute<TUnitOfWork: StateDbUnitOfWork>(
pub fn invoke_read_method<TUnitOfWork: StateDbUnitOfWorkReader>(
&self,
template_id: TemplateId,
method: String,
args: Vec<u8>,
state_db: &mut TUnitOfWork,
) -> Result<(), DigitalAssetError> {
match template_id {
TemplateId::Tip002 => {
tip002_template::invoke_method(method, &args, state_db)?;
},
TemplateId::Tip004 => {
tip004_template::invoke_method(method, &args, state_db)?;
},
TemplateId::Tip721 => {
tip721_template::invoke_method(method, &args, state_db)?;
},
_ => {
instruction: &Instruction,
state_db: &TUnitOfWork,
) -> Result<Option<Vec<u8>>, DigitalAssetError> {
use TemplateId::*;
match instruction.template_id() {
Tip002 => tip002_template::invoke_read_method(instruction.method(), instruction.args(), state_db),
Tip003 => todo!(),
Tip004 => tip004_template::invoke_read_method(instruction.method(), instruction.args(), state_db),
Tip721 => tip721_template::invoke_read_method(instruction.method(), instruction.args(), state_db),
EditableMetadata => {
todo!()
},
}
// let instruction = self.template_factory.create_command(template_id, method, args)?;
// let unit_of_work = state_db.new_unit_of_work();
// let result = instruction.try_execute(db)?;
// unit_of_work.commit()?;
// self.instruction_log.store(hash, result);
// Ok(())
Ok(())
}
}

#[derive(Default, Clone)]
pub struct TemplateFactory {}

impl TemplateFactory {
pub fn init<TUnitOfWork: StateDbUnitOfWork>(
pub fn invoke_write_method<TUnitOfWork: StateDbUnitOfWork>(
&self,
template: &TemplateParameter,
asset_definition: &AssetDefinition,
instruction: &Instruction,
state_db: &mut TUnitOfWork,
) -> Result<(), DigitalAssetError> {
match template.template_id.try_into()? {
TemplateId::Tip002 => tip002_template::init(template, asset_definition, state_db)?,
_ => unimplemented!(),
use TemplateId::*;
match instruction.template_id() {
Tip002 => tip002_template::invoke_write_method(instruction.method(), instruction.args(), state_db),
Tip003 => todo!(),
Tip004 => tip004_template::invoke_write_method(instruction.method(), instruction.args(), state_db),
Tip721 => tip721_template::invoke_write_method(instruction.method(), instruction.args(), state_db),
EditableMetadata => {
todo!()
},
}
Ok(())
}

// pub fn create_command(
// &self,
// _template: TemplateId,
// _method: String,
// _args: VecDeque<Vec<u8>>,
// // caller: InstructionCaller,
// ) -> Result<(), DigitalAssetError> {
// todo!()
// }
}

pub trait InstructionLog {
Expand Down
Loading

0 comments on commit 919678b

Please sign in to comment.