From 197c0b9db84939cf012d2a72315aaed1f639365d Mon Sep 17 00:00:00 2001 From: zeroqn Date: Sun, 18 Aug 2019 18:32:13 +0000 Subject: [PATCH] feat(protocol): Protobuf serialize (#6) * feat(protocol): Add the underlying data structure. * chore(rust-toolchain): bump to nightly-2019-08-01 Fix prost compilation failure. * feat(protocol): add codec trait * feat(protocol): add primitive protobuf structs * feat(protocol): implement conversion for protobuf primitive * feat(protocol): implement ProtocolCodec for protocol primitive * feat(protocol): add transaction protobuf structs * feat(protocol): implement conversion for transaction protobuf * feat(protocol): add *_sync funcs to codec * chore(protocol): rename BytesCodec to ProtocolCodecSync * fix(protocol): clippy warning * chore(protocol): ProtocolCodec::encode now takes mut reference * chore(protocol): add _sync suffix to ProtocolCodecSync funcs * chore(protocol): ProtocolCodec now depends on ProtocolCodecSync Shorten ProtocolCodec trait bound * chore(protocol): rebase to latest master --- protocol/Cargo.toml | 1 + protocol/src/codec/macro.rs | 35 +++ protocol/src/codec/mod.rs | 79 ++++++- protocol/src/codec/primitive.rs | 345 ++++++++++++++++++++++++++++++ protocol/src/codec/transaction.rs | 332 ++++++++++++++++++++++++++++ protocol/src/lib.rs | 2 + protocol/src/types/mod.rs | 8 +- protocol/src/types/primitive.rs | 16 +- rust-toolchain | 2 +- 9 files changed, 808 insertions(+), 12 deletions(-) create mode 100644 protocol/src/codec/macro.rs create mode 100644 protocol/src/codec/primitive.rs create mode 100644 protocol/src/codec/transaction.rs diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 59a9a5ed9..7886ab412 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -14,3 +14,4 @@ bytes = "0.4" sha3 = "0.8" uint = "0.8" hex = "0.3" +prost = "0.5" diff --git a/protocol/src/codec/macro.rs b/protocol/src/codec/macro.rs new file mode 100644 index 000000000..54892b75a --- /dev/null +++ b/protocol/src/codec/macro.rs @@ -0,0 +1,35 @@ +#[macro_export] +macro_rules! field { + ($opt_field:expr, $type:expr, $field:expr) => { + $opt_field.ok_or_else(|| crate::codec::CodecError::MissingField { + r#type: $type, + field: $field, + }) + }; +} + +#[macro_export] +macro_rules! impl_default_bytes_codec_for { + ($category:ident, [$($type:ident),+]) => ( + use crate::types::$category; + + $( + impl ProtocolCodecSync for $category::$type { + fn encode_sync(&self) -> ProtocolResult { + let ser_type = $type::from(self.clone()); + let mut buf = Vec::with_capacity(ser_type.encoded_len()); + + ser_type.encode(&mut buf).map_err(CodecError::from)?; + + Ok(Bytes::from(buf)) + } + + fn decode_sync(bytes: Bytes) -> ProtocolResult { + let ser_type = $type::decode(bytes).map_err(CodecError::from)?; + + $category::$type::try_from(ser_type) + } + } + )+ + ) +} diff --git a/protocol/src/codec/mod.rs b/protocol/src/codec/mod.rs index 31e1bb209..99c10340e 100644 --- a/protocol/src/codec/mod.rs +++ b/protocol/src/codec/mod.rs @@ -1,7 +1,76 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); +// TODO: change Vec to Bytes +// pin: https://github.com/danburkert/prost/pull/190 + +#[macro_use] +mod r#macro; +pub mod primitive; +pub mod transaction; + +use std::error::Error; + +use async_trait::async_trait; +use bytes::Bytes; +use derive_more::{Display, From}; + +use crate::{ProtocolError, ProtocolErrorKind, ProtocolResult}; + +#[async_trait] +pub trait ProtocolCodec: Sized + Send + ProtocolCodecSync { + // Note: We take mut reference so that it can be pinned. This removes Sync + // requirement. + async fn encode(&mut self) -> ProtocolResult; + + async fn decode + Send>(bytes: B) -> ProtocolResult; +} + +// Sync version is still useful in some cases, for example, use in Stream. +// This also work around #[async_trait] problem inside macro +#[doc(hidden)] +pub trait ProtocolCodecSync: Sized + Send { + fn encode_sync(&self) -> ProtocolResult; + + fn decode_sync(bytes: Bytes) -> ProtocolResult; +} + +#[async_trait] +impl ProtocolCodec for T { + async fn encode(&mut self) -> ProtocolResult { + ::encode_sync(self) + } + + async fn decode + Send>(bytes: B) -> ProtocolResult { + let bytes: Bytes = bytes.into(); + + ::decode_sync(bytes) + } +} + +#[derive(Debug, From, Display)] +pub enum CodecError { + #[display(fmt = "prost encode: {}", _0)] + ProtobufEncode(prost::EncodeError), + + #[display(fmt = "prost decode: {}", _0)] + ProtobufDecode(prost::DecodeError), + + #[display(fmt = "{} missing field {}", r#type, field)] + MissingField { + r#type: &'static str, + field: &'static str, + }, + + #[display(fmt = "invalid contract type {}", _0)] + InvalidContractType(i32), + + #[display(fmt = "wrong bytes length: {{ expect: {}, got: {} }}", expect, real)] + WrongBytesLength { expect: usize, real: usize }, +} + +impl Error for CodecError {} + +// TODO: derive macro +impl From for ProtocolError { + fn from(err: CodecError) -> ProtocolError { + ProtocolError::new(ProtocolErrorKind::Codec, Box::new(err)) } } diff --git a/protocol/src/codec/primitive.rs b/protocol/src/codec/primitive.rs new file mode 100644 index 000000000..9ee6f162b --- /dev/null +++ b/protocol/src/codec/primitive.rs @@ -0,0 +1,345 @@ +use std::{convert::TryFrom, default::Default}; + +use bytes::Bytes; +use derive_more::From; +use prost::{Enumeration, Message}; + +use crate::{ + codec::{CodecError, ProtocolCodecSync}, + field, impl_default_bytes_codec_for, + types::primitive as protocol_primitive, + ProtocolError, ProtocolResult, +}; + +// ##################### +// Protobuf +// ##################### + +// TODO: change to Amount? +#[derive(Clone, Message)] +pub struct Balance { + #[prost(bytes, tag = "1")] + pub value: Vec, +} + +#[derive(Clone, Message, From)] +pub struct Hash { + #[prost(bytes, tag = "1")] + pub value: Vec, +} + +#[derive(Clone, Message, From)] +pub struct MerkleRoot { + #[prost(message, tag = "1")] + pub value: Option, +} + +#[derive(Clone, Message, From)] +pub struct AssetID { + #[prost(message, tag = "1")] + pub value: Option, +} + +#[derive(Clone, Message, From)] +pub struct Address { + #[prost(bytes, tag = "1")] + pub value: Vec, +} + +#[derive(Clone, Message)] +pub struct AccountAddress { + #[prost(message, tag = "1")] + pub value: Option
, +} + +#[derive(Clone, Debug, Copy, PartialEq, Eq, Enumeration)] +pub enum ContractType { + Asset = 0, + Library = 1, + App = 2, +} + +#[derive(Clone, Message)] +pub struct ContractAddress { + #[prost(message, tag = "1")] + pub value: Option
, + + #[prost(enumeration = "ContractType", tag = "2")] + pub contract_type: i32, +} + +#[derive(Clone, Message)] +pub struct Asset { + #[prost(message, tag = "1")] + pub id: Option, + + #[prost(string, tag = "2")] + pub name: String, + + #[prost(string, tag = "3")] + pub symbol: String, + + #[prost(message, tag = "4")] + pub supply: Option, + + #[prost(message, tag = "5")] + pub manage_contract: Option, + + #[prost(message, tag = "6")] + pub storage_root: Option, +} + +#[derive(Clone, Message)] +pub struct Fee { + #[prost(message, tag = "1")] + pub asset_id: Option, + + #[prost(uint64, tag = "2")] + pub cycle: u64, +} + +// ##################### +// Conversion +// ##################### + +// Balance + +impl From for Balance { + fn from(balance: protocol_primitive::Balance) -> Balance { + let mut bytes = [0u8; 32]; + balance.to_big_endian(&mut bytes); + + let value = Bytes::from(bytes.as_ref()).to_vec(); + Balance { value } + } +} + +impl TryFrom for protocol_primitive::Balance { + type Error = ProtocolError; + + fn try_from(ser_balance: Balance) -> Result { + let bytes: Bytes = Bytes::from(ser_balance.value); + ensure_len(bytes.len(), 8 * 4)?; + + Ok(protocol_primitive::Balance::from_big_endian(&bytes)) + } +} + +// Hash + +impl From for Hash { + fn from(hash: protocol_primitive::Hash) -> Hash { + let value = hash.as_bytes().to_vec(); + + Hash { value } + } +} + +impl TryFrom for protocol_primitive::Hash { + type Error = ProtocolError; + + fn try_from(hash: Hash) -> Result { + let bytes = Bytes::from(hash.value); + + protocol_primitive::Hash::from_bytes(bytes) + } +} + +// MerkleRoot + +impl From for MerkleRoot { + fn from(root: protocol_primitive::MerkleRoot) -> MerkleRoot { + let value = Some(Hash::from(root)); + + MerkleRoot { value } + } +} + +impl TryFrom for protocol_primitive::MerkleRoot { + type Error = ProtocolError; + + fn try_from(root: MerkleRoot) -> Result { + let hash = field!(root.value, "MerkleRoot", "value")?; + + protocol_primitive::Hash::try_from(hash) + } +} + +// AssetID + +impl From for AssetID { + fn from(id: protocol_primitive::AssetID) -> AssetID { + let value = Some(Hash::from(id)); + + AssetID { value } + } +} + +impl TryFrom for protocol_primitive::AssetID { + type Error = ProtocolError; + + fn try_from(id: AssetID) -> Result { + let hash = field!(id.value, "MerkleRoot", "value")?; + + protocol_primitive::Hash::try_from(hash) + } +} + +// AccountAddress + +impl From for AccountAddress { + fn from(account: protocol_primitive::AccountAddress) -> AccountAddress { + let value = account.as_bytes().to_vec(); + let address = Address { value }; + + AccountAddress { + value: Some(address), + } + } +} + +impl TryFrom for protocol_primitive::AccountAddress { + type Error = ProtocolError; + + fn try_from( + account: AccountAddress, + ) -> Result { + let address = field!(account.value, "AccountAddress", "value")?; + + let bytes = Bytes::from(address.value); + protocol_primitive::AccountAddress::from_bytes(bytes) + } +} + +// ContractAddress + +impl From for ContractAddress { + fn from(contract: protocol_primitive::ContractAddress) -> ContractAddress { + let value = contract.as_bytes().to_vec(); + let address = Some(Address { value }); + + let contract_type = match contract.contract_type() { + protocol_primitive::ContractType::Asset => ContractType::Asset, + protocol_primitive::ContractType::Library => ContractType::Library, + protocol_primitive::ContractType::App => ContractType::App, + }; + + ContractAddress { + value: address, + contract_type: contract_type as i32, + } + } +} + +impl TryFrom for protocol_primitive::ContractAddress { + type Error = ProtocolError; + + fn try_from( + contract: ContractAddress, + ) -> Result { + let address = field!(contract.value, "ContractAddress", "value")?; + + let bytes = Bytes::from(address.value); + protocol_primitive::ContractAddress::from_bytes(bytes) + } +} + +// Asset + +impl From for Asset { + fn from(asset: protocol_primitive::Asset) -> Asset { + let id = AssetID::from(asset.id); + let supply = Balance::from(asset.supply); + let manage_contract = ContractAddress::from(asset.manage_contract); + let storage_root = MerkleRoot::from(asset.storage_root); + + Asset { + id: Some(id), + name: asset.name, + symbol: asset.symbol, + supply: Some(supply), + manage_contract: Some(manage_contract), + storage_root: Some(storage_root), + } + } +} + +impl TryFrom for protocol_primitive::Asset { + type Error = ProtocolError; + + fn try_from(asset: Asset) -> Result { + let id = field!(asset.id, "Asset", "id")?; + let supply = field!(asset.supply, "Asset", "supply")?; + let manage_contract = field!(asset.manage_contract, "Asset", "manage_contract")?; + let storage_root = field!(asset.storage_root, "Asset", "storage_root")?; + + let asset = protocol_primitive::Asset { + id: protocol_primitive::AssetID::try_from(id)?, + name: asset.name, + symbol: asset.symbol, + supply: protocol_primitive::Balance::try_from(supply)?, + manage_contract: protocol_primitive::ContractAddress::try_from(manage_contract)?, + storage_root: protocol_primitive::MerkleRoot::try_from(storage_root)?, + }; + + Ok(asset) + } +} + +// Fee + +impl From for Fee { + fn from(fee: protocol_primitive::Fee) -> Fee { + let id_hash = Hash::from(fee.asset_id); + let asset_id = AssetID { + value: Some(id_hash), + }; + + Fee { + asset_id: Some(asset_id), + cycle: fee.cycle, + } + } +} + +impl TryFrom for protocol_primitive::Fee { + type Error = ProtocolError; + + fn try_from(fee: Fee) -> Result { + let asset_id = field!(fee.asset_id, "Fee", "asset_id")?; + let id_hash = field!(asset_id.value, "Fee", "asset_id")?; + + let fee = protocol_primitive::Fee { + asset_id: protocol_primitive::Hash::try_from(id_hash)?, + cycle: fee.cycle, + }; + + Ok(fee) + } +} + +// ##################### +// Codec +// ##################### + +// MerkleRoot and AssetID are just Hash aliases +impl_default_bytes_codec_for!(primitive, [ + Balance, + Hash, + AccountAddress, + ContractAddress, + Asset, + Fee +]); + +// ##################### +// Util +// ##################### + +fn ensure_len(real: usize, expect: usize) -> Result<(), CodecError> { + if real != expect { + return Err(CodecError::WrongBytesLength { expect, real }); + } + + Ok(()) +} diff --git a/protocol/src/codec/transaction.rs b/protocol/src/codec/transaction.rs new file mode 100644 index 000000000..af77c8aee --- /dev/null +++ b/protocol/src/codec/transaction.rs @@ -0,0 +1,332 @@ +use std::convert::TryFrom; + +use bytes::Bytes; +use prost::Message; + +use crate::{ + codec::{ + primitive::{AccountAddress, AssetID, Balance, ContractAddress, ContractType, Fee, Hash}, + CodecError, ProtocolCodecSync, + }, + field, impl_default_bytes_codec_for, + types::primitive as protocol_primitive, + ProtocolError, ProtocolResult, +}; + +use prost::Oneof; + +#[derive(Clone, Message)] +pub struct Transfer { + #[prost(message, tag = "1")] + pub receiver: Option, + + #[prost(message, tag = "2")] + pub asset_id: Option, + + #[prost(message, tag = "3")] + pub amount: Option, +} + +#[derive(Clone, Message)] +pub struct Approve { + #[prost(message, tag = "1")] + pub spender: Option, + + #[prost(message, tag = "2")] + pub asset_id: Option, + + #[prost(message, tag = "3")] + pub max: Option, +} + +#[derive(Clone, Message)] +pub struct Deploy { + #[prost(bytes, tag = "1")] + pub code: Vec, + + #[prost(enumeration = "ContractType", tag = "2")] + pub contract_type: i32, +} + +#[derive(Clone, Message)] +pub struct Call { + #[prost(message, tag = "1")] + pub contract: Option, + + #[prost(string, tag = "2")] + pub method: String, + + #[prost(bytes, repeated, tag = "3")] + pub args: Vec>, + + #[prost(message, tag = "4")] + pub asset_id: Option, + + #[prost(message, tag = "5")] + pub amount: Option, +} + +#[derive(Clone, Oneof)] +pub enum TransactionAction { + #[prost(message, tag = "5")] + Transfer(Transfer), + + #[prost(message, tag = "6")] + Approve(Approve), + + #[prost(message, tag = "7")] + Deploy(Deploy), + + #[prost(message, tag = "8")] + Call(Call), +} + +#[derive(Clone, Message)] +pub struct RawTransaction { + #[prost(message, tag = "1")] + pub chain_id: Option, + + #[prost(message, tag = "2")] + pub nonce: Option, + + #[prost(uint64, tag = "3")] + pub timeout: u64, + + #[prost(message, tag = "4")] + pub fee: Option, + + #[prost(oneof = "TransactionAction", tags = "5, 6, 7, 8")] + pub action: Option, +} + +#[derive(Clone, Message)] +pub struct SignedTransaction { + #[prost(message, tag = "1")] + pub raw: Option, + + #[prost(message, tag = "2")] + pub tx_hash: Option, + + #[prost(bytes, tag = "3")] + pub pubkey: Vec, + + #[prost(bytes, tag = "4")] + pub signature: Vec, +} + +// ################# +// Conversion +// ################# + +// TransactionAction + +impl From for TransactionAction { + fn from(action: transaction::TransactionAction) -> TransactionAction { + match action { + transaction::TransactionAction::Transfer { + receiver, + asset_id, + amount, + } => { + let transfer = Transfer { + receiver: Some(AccountAddress::from(receiver)), + asset_id: Some(AssetID::from(asset_id)), + amount: Some(Balance::from(amount)), + }; + + TransactionAction::Transfer(transfer) + } + transaction::TransactionAction::Approve { + spender, + asset_id, + max, + } => { + let approve = Approve { + spender: Some(ContractAddress::from(spender)), + asset_id: Some(AssetID::from(asset_id)), + max: Some(Balance::from(max)), + }; + + TransactionAction::Approve(approve) + } + transaction::TransactionAction::Deploy { + code, + contract_type, + } => { + let deploy = Deploy { + code: code.to_vec(), + contract_type: contract_type as i32, + }; + + TransactionAction::Deploy(deploy) + } + transaction::TransactionAction::Call { + contract, + method, + args, + asset_id, + amount, + } => { + let args = args.into_iter().map(|arg| arg.to_vec()).collect::>(); + + let call = Call { + contract: Some(ContractAddress::from(contract)), + method, + args, + asset_id: Some(AssetID::from(asset_id)), + amount: Some(Balance::from(amount)), + }; + + TransactionAction::Call(call) + } + } + } +} + +impl TryFrom for transaction::TransactionAction { + type Error = ProtocolError; + + fn try_from(action: TransactionAction) -> Result { + match action { + TransactionAction::Transfer(transfer) => { + let receiver = + field!(transfer.receiver, "TransactionAction::Transfer", "receiver")?; + let asset_id = + field!(transfer.asset_id, "TransactionAction::Transfer", "asset_id")?; + let amount = field!(transfer.amount, "TransactionAction::Transfer", "amount")?; + + let action = transaction::TransactionAction::Transfer { + receiver: protocol_primitive::AccountAddress::try_from(receiver)?, + asset_id: protocol_primitive::AssetID::try_from(asset_id)?, + amount: protocol_primitive::Balance::try_from(amount)?, + }; + + Ok(action) + } + TransactionAction::Approve(approve) => { + let spender = field!(approve.spender, "TransactionAction::Approve", "spender")?; + let asset_id = field!(approve.asset_id, "TransactionAction::Approve", "asset_id")?; + let max = field!(approve.max, "TransactionAction::Approve", "max")?; + + let action = transaction::TransactionAction::Approve { + spender: protocol_primitive::ContractAddress::try_from(spender)?, + asset_id: protocol_primitive::AssetID::try_from(asset_id)?, + max: protocol_primitive::Balance::try_from(max)?, + }; + + Ok(action) + } + TransactionAction::Deploy(deploy) => { + let contract_type = match deploy.contract_type { + 0 => protocol_primitive::ContractType::Asset, + 1 => protocol_primitive::ContractType::Library, + 2 => protocol_primitive::ContractType::App, + _ => return Err(CodecError::InvalidContractType(deploy.contract_type).into()), + }; + + let action = transaction::TransactionAction::Deploy { + code: Bytes::from(deploy.code), + contract_type, + }; + + Ok(action) + } + TransactionAction::Call(call) => { + let contract = field!(call.contract, "TransactionAction::Call", "contract")?; + let asset_id = field!(call.asset_id, "Transaction::Call", "asset_id")?; + let amount = field!(call.amount, "Transaction::Call", "amount")?; + let args = call.args.into_iter(); + + let action = transaction::TransactionAction::Call { + contract: protocol_primitive::ContractAddress::try_from(contract)?, + method: call.method, + args: args.map(Bytes::from).collect::>(), + asset_id: protocol_primitive::AssetID::try_from(asset_id)?, + amount: protocol_primitive::Balance::try_from(amount)?, + }; + + Ok(action) + } + } + } +} + +// RawTransaction + +impl From for RawTransaction { + fn from(raw: transaction::RawTransaction) -> RawTransaction { + let chain_id = Some(Hash::from(raw.chain_id)); + let nonce = Some(Hash::from(raw.nonce)); + let fee = Some(Fee::from(raw.fee)); + let action = Some(TransactionAction::from(raw.action)); + + RawTransaction { + chain_id, + nonce, + timeout: raw.timeout, + fee, + action, + } + } +} + +impl TryFrom for transaction::RawTransaction { + type Error = ProtocolError; + + fn try_from(raw: RawTransaction) -> Result { + let chain_id = field!(raw.chain_id, "RawTransaction", "chain_id")?; + let nonce = field!(raw.nonce, "RawTransaction", "nonce")?; + let fee = field!(raw.fee, "RawTransaction", "fee")?; + let action = field!(raw.action, "RawTransaction", "action")?; + + let raw_tx = transaction::RawTransaction { + chain_id: protocol_primitive::Hash::try_from(chain_id)?, + nonce: protocol_primitive::Hash::try_from(nonce)?, + timeout: raw.timeout, + fee: protocol_primitive::Fee::try_from(fee)?, + action: transaction::TransactionAction::try_from(action)?, + }; + + Ok(raw_tx) + } +} + +// SignedTransaction + +impl From for SignedTransaction { + fn from(stx: transaction::SignedTransaction) -> SignedTransaction { + let raw = RawTransaction::from(stx.raw); + let tx_hash = Hash::from(stx.tx_hash); + + SignedTransaction { + raw: Some(raw), + tx_hash: Some(tx_hash), + pubkey: stx.pubkey.to_vec(), + signature: stx.signature.to_vec(), + } + } +} + +impl TryFrom for transaction::SignedTransaction { + type Error = ProtocolError; + + fn try_from(stx: SignedTransaction) -> Result { + let raw = field!(stx.raw, "SignedTransaction", "raw")?; + let tx_hash = field!(stx.tx_hash, "SignedTransaction", "tx_hash")?; + + let stx = transaction::SignedTransaction { + raw: transaction::RawTransaction::try_from(raw)?, + tx_hash: protocol_primitive::Hash::try_from(tx_hash)?, + pubkey: Bytes::from(stx.pubkey), + signature: Bytes::from(stx.signature), + }; + + Ok(stx) + } +} + +// ################# +// Codec +// ################# + +impl_default_bytes_codec_for!(transaction, [RawTransaction, SignedTransaction]); diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index 8a300da3a..2b1993c4b 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(async_await)] + #[macro_use] extern crate uint; #[macro_use] diff --git a/protocol/src/types/mod.rs b/protocol/src/types/mod.rs index e5feeb008..a24da5320 100644 --- a/protocol/src/types/mod.rs +++ b/protocol/src/types/mod.rs @@ -1,7 +1,7 @@ -mod epoch; -mod primitive; -mod receipt; -mod transaction; +pub(crate) mod epoch; +pub(crate) mod primitive; +pub(crate) mod receipt; +pub(crate) mod transaction; use std::error::Error; diff --git a/protocol/src/types/primitive.rs b/protocol/src/types/primitive.rs index 749c97c43..4d156327f 100644 --- a/protocol/src/types/primitive.rs +++ b/protocol/src/types/primitive.rs @@ -161,7 +161,10 @@ impl AccountAddress { } pub fn as_bytes(&self) -> Bytes { - self.inner.as_bytes() + let mut bytes = Bytes::from([ACCOUNT_ADDRESS_MAGIC].as_ref()); + bytes.extend_from_slice(&self.inner.as_bytes()); + + bytes } } @@ -203,7 +206,16 @@ impl ContractAddress { } pub fn as_bytes(&self) -> Bytes { - self.inner.as_bytes() + let magic = match self.contract_type() { + ContractType::Asset => ASSET_CONTRACT_ADDRESS_MAGIC, + ContractType::Library => LIBRARY_CONTRACT_ADDRESS_MAGIC, + ContractType::App => APP_CONTRACT_ADDRESS_MAGIC, + }; + + let mut bytes = Bytes::from([magic].as_ref()); + bytes.extend_from_slice(&self.inner.as_bytes()); + + bytes } pub fn contract_type(&self) -> ContractType { diff --git a/rust-toolchain b/rust-toolchain index ec70ae5ff..4390c8a28 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2019-07-19 +nightly-2019-08-01