Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from broxus:master #15

Merged
merged 8 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 97 additions & 4 deletions nekoton-abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use ton_block::{
};
use ton_executor::{BlockchainConfig, OrdinaryTransactionExecutor, TransactionExecutor};
use ton_types::{SliceData, UInt256};
use ton_vm::executor::BehaviorModifiers;

#[cfg(feature = "derive")]
pub use {
Expand All @@ -86,8 +87,8 @@ pub use self::models::*;
pub use self::token_packer::*;
pub use self::token_unpacker::*;
pub use self::tokens_json::*;
pub use self::tvm::BriefBlockchainConfig;
pub use transaction_parser::TransactionParser;
pub use self::transaction_parser::TransactionParser;
pub use self::tvm::{BriefBlockchainConfig, StackItem, VmGetterOutput};

mod abi_helpers;
mod code_salt;
Expand All @@ -100,7 +101,7 @@ mod token_packer;
mod token_unpacker;
mod tokens_json;
pub mod transaction_parser;
mod tvm;
pub mod tvm;

pub fn read_function_id(data: &SliceData) -> Result<u32> {
let mut value: u32 = 0;
Expand Down Expand Up @@ -582,6 +583,76 @@ impl<'a> ExecutionContext<'a> {
) -> Result<ExecutionOutput> {
function.run_local_responsible(self.clock, self.account_stuff.clone(), input)
}

pub fn run_getter<M>(
&self,
method_id: &M,
args: &[StackItem],
) -> Result<VmGetterOutput, tvm::ExecutionError>
where
M: AsGetterMethodId + ?Sized,
{
self.run_getter_ext(
method_id,
args,
&BriefBlockchainConfig::default(),
&Default::default(),
)
}

pub fn run_getter_ext<M>(
&self,
method_id: &M,
args: &[StackItem],
config: &BriefBlockchainConfig,
modifier: &BehaviorModifiers,
) -> Result<VmGetterOutput, tvm::ExecutionError>
where
M: AsGetterMethodId + ?Sized,
{
let BlockStats {
gen_utime, gen_lt, ..
} = get_block_stats(self.clock, None, self.account_stuff.storage.last_trans_lt);

tvm::call_getter(
gen_utime,
gen_lt,
self.account_stuff,
method_id.as_getter_method_id(),
args,
config,
modifier,
)
}
}

pub trait AsGetterMethodId {
fn as_getter_method_id(&self) -> u32;
}

impl<T: AsGetterMethodId + ?Sized> AsGetterMethodId for &T {
fn as_getter_method_id(&self) -> u32 {
T::as_getter_method_id(*self)
}
}

impl<T: AsGetterMethodId + ?Sized> AsGetterMethodId for &mut T {
fn as_getter_method_id(&self) -> u32 {
T::as_getter_method_id(*self)
}
}

impl AsGetterMethodId for u32 {
fn as_getter_method_id(&self) -> u32 {
*self
}
}

impl AsGetterMethodId for str {
fn as_getter_method_id(&self) -> u32 {
let crc = crc_16(self.as_bytes());
crc as u32 | 0x10000
}
}

pub trait FunctionExt {
Expand Down Expand Up @@ -739,7 +810,14 @@ impl<'a> FunctionAbi<'a> {
let tvm::ActionPhaseOutput {
messages,
exit_code: result_code,
} = tvm::call_msg(gen_utime, gen_lt, account_stuff, &msg, config)?;
} = tvm::call_msg(
gen_utime,
gen_lt,
account_stuff,
&msg,
config,
&Default::default(),
)?;

let tokens = if let Some(answer_id) = answer_id {
messages.map(|messages| {
Expand Down Expand Up @@ -1172,6 +1250,21 @@ mod tests {
assert_eq!(decoded_comment, comment);
}

#[test]
fn execute_getter() {
let cell = ton_types::deserialize_tree_of_cells(&mut base64::decode("te6ccgEBAwEA1wACcIAStWnZig414CoO3Ix5SSSgxF+4p0D15b9rxM7Q6hTG2AQNApWGauQIQAABez2Soaga3FkkG3ymAgEAUAAACtJLqS2Krp5U49k0sATqkF/7CPTREi6T4gLBqodDaVGp3w9YHEEA3v8AIN0gggFMl7ohggEznLqxn3Gw7UTQ0x/THzHXC//jBOCk8mCDCNcYINMf0x/TH/gjE7vyY+1E0NMf0x/T/9FRMrryoVFEuvKiBPkBVBBV+RDyo/gAkyDXSpbTB9QC+wDo0QGkyMsfyx/L/8ntVA==").unwrap().as_slice()).unwrap();
let state = nekoton_utils::deserialize_account_stuff(cell).unwrap();

let res = ExecutionContext {
clock: &SimpleClock,
account_stuff: &state,
}
.run_getter("seqno", &[])
.unwrap();

println!("{res:?}");
}

#[test]
fn test_encode_cell() {
let expected = "te6ccgEBAQEAIgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADA5";
Expand Down
47 changes: 42 additions & 5 deletions nekoton-abi/src/tvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use ton_block::{
use ton_types::SliceData;
use ton_vm::executor::gas::gas_state::Gas;
use ton_vm::stack::integer::IntegerData;
use ton_vm::stack::{savelist::SaveList, Stack, StackItem};
use ton_vm::stack::{savelist::SaveList, Stack};

pub type BehaviorModifiers = ton_vm::executor::BehaviorModifiers;
pub type StackItem = ton_vm::stack::StackItem;

#[derive(Debug, Copy, Clone)]
pub struct BriefBlockchainConfig {
Expand Down Expand Up @@ -43,11 +46,12 @@ impl From<ton_executor::BlockchainConfig> for BriefBlockchainConfig {
pub fn call(
utime: u32,
lt: u64,
account: &mut AccountStuff,
account: &AccountStuff,
stack: Stack,
config: &BriefBlockchainConfig,
modifiers: &BehaviorModifiers,
) -> Result<(ton_vm::executor::Engine, i32, bool), ExecutionError> {
let state = match &mut account.storage.state {
let state = match &account.storage.state {
ton_block::AccountState::AccountActive { state_init, .. } => Ok(state_init),
_ => Err(ExecutionError::AccountIsNotActive),
}?;
Expand Down Expand Up @@ -85,6 +89,7 @@ pub fn call(
Some(gas),
);
engine.set_signature_id(config.global_id);
engine.modify_behavior(modifiers.clone());

let result = engine.execute();

Expand Down Expand Up @@ -112,6 +117,7 @@ pub fn call_msg(
account: &mut AccountStuff,
msg: &Message,
config: &BriefBlockchainConfig,
modifiers: &ton_vm::executor::BehaviorModifiers,
) -> Result<ActionPhaseOutput, ExecutionError> {
let msg_cell = msg
.write_to_new_cell()
Expand All @@ -135,7 +141,7 @@ pub fn call_msg(
.push(StackItem::Slice(msg.body().unwrap_or_default())) // message body
.push(function_selector); // function selector

let (engine, exit_code, success) = call(utime, lt, account, stack, config)?;
let (engine, exit_code, success) = call(utime, lt, account, stack, config, modifiers)?;
if !success {
return Ok(ActionPhaseOutput {
messages: None,
Expand Down Expand Up @@ -166,6 +172,37 @@ pub fn call_msg(
})
}

pub fn call_getter(
utime: u32,
lt: u64,
account: &AccountStuff,
method_id: u32,
args: &[ton_vm::stack::StackItem],
config: &BriefBlockchainConfig,
modifiers: &ton_vm::executor::BehaviorModifiers,
) -> Result<VmGetterOutput, ExecutionError> {
let mut stack = Stack::new();
for arg in args {
stack.push(arg.clone());
}
stack.push(ton_vm::int!(method_id));

let (mut engine, exit_code, is_ok) = call(utime, lt, account, stack, config, modifiers)?;

Ok(VmGetterOutput {
stack: engine.withdraw_stack().storage,
exit_code,
is_ok,
})
}

#[derive(Debug, Clone)]
pub struct VmGetterOutput {
pub stack: Vec<ton_vm::stack::StackItem>,
pub exit_code: i32,
pub is_ok: bool,
}

fn build_contract_info(
address: &MsgAddressInt,
balance: &CurrencyCollection,
Expand All @@ -192,7 +229,7 @@ pub struct ActionPhaseOutput {
pub exit_code: i32,
}

#[derive(thiserror::Error, Debug)]
#[derive(thiserror::Error, Debug, Clone, Copy)]
pub enum ExecutionError {
#[error("Failed to serialize message")]
FailedToSerializeMessage,
Expand Down
1 change: 1 addition & 0 deletions nekoton-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub mod tip3_1;
pub mod tip3_any;
pub mod tip4_1;
pub mod tip4_2;
pub mod tip4_2_2;
pub mod tip4_3;
pub mod tip6;
pub mod wallets;
Expand Down
2 changes: 1 addition & 1 deletion nekoton-contracts/src/tip4_2/metadata_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ton_abi::{Param, ParamType};

pub const INTERFACE_ID: u32 = 0x24D7D5F5;

///Get NFT metadata in JSON format
/// Get NFT metadata in JSON format
///
/// # Type
/// Responsible getter method
Expand Down
26 changes: 26 additions & 0 deletions nekoton-contracts/src/tip4_2_2/collection_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::utils::declare_function;
use ton_abi::{Param, ParamType};

pub const INTERFACE_ID: u32 = 0x244a5200;

/// Build url to get metadata for NFT.
///
/// # Type
/// Responsible getter method
///
/// # Inputs
/// * `answerId: uint32` - responsible answer id
/// * `part: cell` - encoded URL part
///
/// # Outputs
/// * `nftUrl: string` - NFT metadata URL
pub fn get_nft_url() -> &'static ton_abi::Function {
declare_function! {
name: "getNftUrl",
inputs: vec![
Param::new("answerId", ParamType::Uint(32)),
Param::new("part", ParamType::Cell),
],
outputs: vec![Param::new("nftUrl", ParamType::String)]
}
}
19 changes: 19 additions & 0 deletions nekoton-contracts/src/tip4_2_2/metadata_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use crate::utils::declare_function;
use ton_abi::{Param, ParamType};

pub const INTERFACE_ID: u32 = 0x7239d7b1;

/// Get URL parts identifying the NFT.
///
/// # Type
/// Responsible getter method
///
/// # Outputs
/// * `part: cell` - encoded URL part
pub fn get_url_parts() -> &'static ton_abi::Function {
declare_function! {
name: "getUrlParts",
inputs: vec![Param::new("answerId", ParamType::Uint(32))],
outputs: vec![Param::new("part", ParamType::Cell)]
}
}
38 changes: 38 additions & 0 deletions nekoton-contracts/src/tip4_2_2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::RunLocalSimple;
use anyhow::Result;
use nekoton_abi::ExecutionContext;
use nekoton_abi::*;

pub mod collection_contract;
pub mod metadata_contract;

#[derive(Copy, Clone)]
pub struct MetadataContract<'a>(pub ExecutionContext<'a>);

impl MetadataContract<'_> {
pub fn get_url_parts(&self) -> Result<String> {
let inputs = [0u32.token_value().named("answerId")];
let result = self
.0
.run_local_responsible_simple(metadata_contract::get_url_parts(), &inputs)?
.unpack_first()?;
Ok(result)
}
}

#[derive(Copy, Clone)]
pub struct CollectionContract<'a>(pub ExecutionContext<'a>);

impl CollectionContract<'_> {
pub fn get_nft_url(&self, part: ton_types::Cell) -> Result<String> {
let inputs = [
0u32.token_value().named("answerId"),
part.token_value().named("part"),
];
let result = self
.0
.run_local_responsible_simple(collection_contract::get_nft_url(), &inputs)?
.unpack_first()?;
Ok(result)
}
}
3 changes: 3 additions & 0 deletions nekoton-proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ ton_block = { git = "https://github.com/broxus/ton-labs-block.git" }
ton_types = { git = "https://github.com/broxus/ton-labs-types" }

nekoton-abi = { path = "../nekoton-abi"}

[dev-dependencies]
base64 = "0.13"
Loading
Loading