Skip to content

Commit fd9462b

Browse files
authored
Merge pull request #128 from tonlabs/updated-contract
Updated contract
2 parents 4f27347 + ed22514 commit fd9462b

File tree

8 files changed

+156
-83
lines changed

8 files changed

+156
-83
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Release Notes
22
All notable changes to this project will be documented in this file.
33

4+
## Jun 03, 2020
5+
### New
6+
- local run functions return updated contract state when running with `full_run = true`
7+
48
## May 28, 2020
59
### New
610
- error resolving by local message processing

ton_client/client/src/contracts/run.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,14 @@ pub struct ParamsOfDecodeUnknownRun {
123123
#[derive(Serialize, Deserialize)]
124124
pub(crate) struct ResultOfRun {
125125
pub output: serde_json::Value,
126-
pub fees: Option<RunFees>
126+
pub fees: RunFees
127+
}
128+
129+
#[derive(Serialize, Deserialize)]
130+
pub(crate) struct ResultOfLocalRun {
131+
pub output: serde_json::Value,
132+
pub fees: Option<RunFees>,
133+
pub account: Option<Contract>
127134
}
128135

129136
#[derive(Serialize, Deserialize)]
@@ -264,7 +271,7 @@ pub(crate) fn process_transaction(
264271
let fees = transaction.calc_fees().into();
265272
let output = process_out_messages(&transaction.out_messages, abi, function)?;
266273

267-
Ok( ResultOfRun { output, fees: Some(fees) } )
274+
Ok( ResultOfRun { output, fees: fees } )
268275
}
269276

270277
pub(crate) fn serialize_message(msg: TvmMessage) -> ApiResult<(Vec<u8>, String)> {
@@ -274,7 +281,7 @@ pub(crate) fn serialize_message(msg: TvmMessage) -> ApiResult<(Vec<u8>, String)>
274281
Ok((msg, id.to_string()))
275282
}
276283

277-
pub(crate) fn local_run(context: &mut ClientContext, params: ParamsOfLocalRun) -> ApiResult<ResultOfRun> {
284+
pub(crate) fn local_run(context: &mut ClientContext, params: ParamsOfLocalRun) -> ApiResult<ResultOfLocalRun> {
278285
debug!("-> contracts.run.local({}, {:?})",
279286
params.address.clone(),
280287
params.call_set.clone()
@@ -293,7 +300,7 @@ pub(crate) fn local_run(context: &mut ClientContext, params: ParamsOfLocalRun) -
293300
Some(context), params.call_set, key_pair.as_ref(), address, account, params.full_run, params.time)
294301
}
295302

296-
pub(crate) fn local_run_msg(context: &mut ClientContext, params: ParamsOfLocalRunWithMsg) -> ApiResult<ResultOfRun> {
303+
pub(crate) fn local_run_msg(context: &mut ClientContext, params: ParamsOfLocalRunWithMsg) -> ApiResult<ResultOfLocalRun> {
297304
debug!("-> contracts.run.local.msg({}, {}, {})",
298305
params.address.clone(),
299306
params.function_name.clone().unwrap_or_default(),
@@ -538,7 +545,7 @@ pub(crate) fn do_local_run(
538545
account: Option<Contract>,
539546
full_run: bool,
540547
time: Option<u32>,
541-
) -> ApiResult<ResultOfRun> {
548+
) -> ApiResult<ResultOfLocalRun> {
542549

543550
let msg = Contract::construct_call_message_json(
544551
address.clone(), call_set.clone().into(), false, keys, None, None)
@@ -564,7 +571,7 @@ pub(crate) fn do_local_run_msg(
564571
msg: TvmMessage,
565572
full_run: bool,
566573
time: Option<u32>,
567-
) -> ApiResult<ResultOfRun> {
574+
) -> ApiResult<ResultOfLocalRun> {
568575

569576
let contract = match account {
570577
// load contract data from node manually
@@ -593,7 +600,7 @@ pub(crate) fn do_local_run_msg(
593600
};
594601

595602
if full_run {
596-
let transaction = contract.local_call(msg, time)
603+
let result = contract.local_call(msg, time)
597604
.map_err(|err|
598605
match err.downcast_ref::<ton_sdk::SdkError>() {
599606
Some(ton_sdk::SdkError::ContractError(exit_code)) =>
@@ -602,14 +609,20 @@ pub(crate) fn do_local_run_msg(
602609
ApiError::low_balance(&address),
603610
_ => ApiError::contracts_local_run_failed(err)
604611
})?;
605-
process_transaction(transaction, abi, function_name, &address, false)
612+
let run_result = process_transaction(result.transaction, abi, function_name, &address, false)?;
613+
Ok(ResultOfLocalRun {
614+
output: run_result.output,
615+
fees: Some(run_result.fees),
616+
account: Some(result.updated_account),
617+
})
606618
} else {
607619
let messages = contract.local_call_tvm(msg)
608620
.map_err(|err| ApiError::contracts_local_run_failed(err))?;
609621

610-
Ok(ResultOfRun {
622+
Ok(ResultOfLocalRun {
611623
output: process_out_messages(&messages, abi, function_name)?,
612-
fees: None
624+
fees: None,
625+
account: None
613626
})
614627
}
615628
}

ton_sdk/src/contract.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -156,28 +156,29 @@ const ACCOUNT_FIELDS: &str = r#"
156156
"#;
157157

158158
// The struct represents value of some addititonal currency
159-
#[derive(Deserialize, Default, Debug, Clone)]
159+
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
160160
pub struct OtherCurrencyValue {
161161
currency: u32,
162-
value: u128,
162+
#[serde(with = "json_helper::uint")]
163+
value: u64,
163164
}
164165

165166
// The struct represents smart contract and allows
166167
// to deploy and call it, to get some contract's properties.
167168
// Don't forget - in TON blockchain Contract and Account are the same substances.
168-
#[derive(Deserialize, Default, Debug)]
169+
#[derive(Serialize, Deserialize, Default, Debug)]
169170
#[serde(default)]
170171
pub struct Contract {
171-
#[serde(deserialize_with = "json_helper::deserialize_address_int_from_string")]
172+
#[serde(with = "json_helper::address")]
172173
pub id: MsgAddressInt,
173-
#[serde(deserialize_with = "json_helper::deserialize_account_status")]
174+
#[serde(with = "json_helper::account_status")]
174175
pub acc_type: AccountStatus,
175-
#[serde(deserialize_with = "json_helper::deserialize_uint_from_string")]
176+
#[serde(with = "json_helper::uint")]
176177
pub balance: u64,
177178
pub balance_other: Option<Vec<OtherCurrencyValue>>,
178-
#[serde(deserialize_with = "json_helper::deserialize_tree_of_cells_opt_cell")]
179+
#[serde(with = "json_helper::opt_cell")]
179180
pub code: Option<Cell>,
180-
#[serde(deserialize_with = "json_helper::deserialize_tree_of_cells_opt_cell")]
181+
#[serde(with = "json_helper::opt_cell")]
181182
pub data: Option<Cell>,
182183
pub last_paid: u32,
183184
}
@@ -644,6 +645,12 @@ pub struct MessageToSign {
644645
pub expire: Option<u32>,
645646
}
646647

648+
pub struct LocalCallResult {
649+
pub transaction: Transaction,
650+
pub updated_account: Contract,
651+
pub updated_account_root: Cell
652+
}
653+
647654
impl Contract {
648655
/// Returns contract's address
649656
pub fn address(&self) -> MsgAddressInt {
@@ -694,7 +701,7 @@ impl Contract {
694701
|currency, value| -> Result<bool> {
695702
balance_other.push(OtherCurrencyValue {
696703
currency,
697-
value: num_traits::ToPrimitive::to_u128(value.value()).ok_or(
704+
value: num_traits::ToPrimitive::to_u64(value.value()).ok_or(
698705
error!(SdkError::InvalidData { msg: "Account's other currency balance is too big".to_owned() })
699706
)?,
700707
});
@@ -797,15 +804,21 @@ impl Contract {
797804

798805
/// Invokes local transaction executor instance with provided inbound message.
799806
/// Returns outbound messages generated by contract function and transaction fees
800-
pub fn local_call(&self, message: TvmMessage, time: Option<u32>) -> Result<Transaction> {
807+
pub fn local_call(&self, message: TvmMessage, time: Option<u32>) -> Result<LocalCallResult> {
801808
// TODO: get real config
802-
let transaction = local_tvm::executor::call_executor(
809+
let (transaction, account_root) = local_tvm::executor::call_executor(
803810
self.to_account()?,
804811
message,
805812
BlockchainConfig::default(),
806813
time.unwrap_or(Self::now()))?;
807814

808-
Transaction::try_from(transaction)
815+
let transaction = Transaction::try_from(transaction)?;
816+
let updated_account = Self::from_cells(account_root.clone().into())?;
817+
Ok(LocalCallResult {
818+
transaction,
819+
updated_account,
820+
updated_account_root: account_root
821+
})
809822
}
810823

811824
/// Invokes local transaction executor instance with provided inbound message.
@@ -818,7 +831,7 @@ impl Contract {
818831
abi: String,
819832
key_pair: Option<&Keypair>,
820833
time: Option<u32>
821-
) -> Result<Transaction> {
834+
) -> Result<LocalCallResult> {
822835
// pack params into bag of cells via ABI
823836
let msg_body = ton_abi::encode_function_call(abi, func, header, input, false, key_pair)?;
824837

ton_sdk/src/json_helper.rs

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,34 @@ impl<'de> serde::de::Visitor<'de> for U8Visitor {
6464
}
6565
}
6666

67+
pub mod opt_cell {
68+
use super::*;
69+
70+
pub fn deserialize<'de, D>(d: D) -> Result<Option<Cell>, D::Error>
71+
where D: serde::Deserializer<'de>
72+
{
73+
let b64 = d.deserialize_option(StringVisitor)?;
74+
75+
if "null" == b64 {
76+
Ok(None)
77+
} else {
78+
Ok(Some(deserialize_tree_of_cells_from_base64::<D>(&b64)?))
79+
}
80+
}
81+
82+
pub fn serialize<S>(value: &Option<Cell>, serializer: S) -> Result<S::Ok, S::Error>
83+
where S: serde::Serializer
84+
{
85+
if let Some(cell) = value {
86+
let str_value = base64::encode(&ton_types::serialize_toc(&cell).map_err(|err|
87+
serde::ser::Error::custom(format!("Cannot serialize BOC: {}", err)))?);
88+
serializer.serialize_some(&str_value)
89+
} else {
90+
serializer.serialize_none()
91+
}
92+
}
93+
}
94+
6795
pub fn deserialize_tree_of_cells_from_base64<'de, D>(b64: &str) -> Result<Cell, D::Error>
6896
where D: serde::Deserializer<'de>
6997
{
@@ -74,42 +102,50 @@ pub fn deserialize_tree_of_cells_from_base64<'de, D>(b64: &str) -> Result<Cell,
74102
.map_err(|err| D::Error::custom(format!("BOC read error: {}", err)))
75103
}
76104

77-
pub fn deserialize_tree_of_cells_opt_cell<'de, D>(d: D) -> Result<Option<Cell>, D::Error>
78-
where D: serde::Deserializer<'de>
79-
{
80-
let b64 = d.deserialize_option(StringVisitor)?;
105+
pub mod address {
106+
use super::*;
107+
108+
pub fn deserialize<'de, D>(d: D) -> Result<MsgAddressInt, D::Error>
109+
where D: serde::Deserializer<'de>
110+
{
111+
let string = d.deserialize_string(StringVisitor)?;
81112

82-
if "null" == b64 {
83-
Ok(None)
84-
} else {
85-
Ok(Some(deserialize_tree_of_cells_from_base64::<D>(&b64)?))
113+
MsgAddressInt::from_str(&string)
114+
.map_err(|err| D::Error::custom(format!("Address parsing error: {}", err)))
115+
}
116+
117+
pub fn serialize<S>(value: &MsgAddressInt, serializer: S) -> Result<S::Ok, S::Error>
118+
where S: serde::Serializer
119+
{
120+
serializer.serialize_str(&value.to_string())
86121
}
87122
}
88123

89-
pub fn deserialize_address_int_from_string<'de, D>(d: D) -> Result<MsgAddressInt, D::Error>
90-
where D: serde::Deserializer<'de>
91-
{
92-
let string = d.deserialize_string(StringVisitor)?;
124+
pub mod uint {
125+
use super::*;
93126

94-
MsgAddressInt::from_str(&string)
95-
.map_err(|err| D::Error::custom(format!("Address parsing error: {}", err)))
96-
}
127+
pub fn deserialize<'de, D>(d: D) -> Result<u64, D::Error>
128+
where D: serde::Deserializer<'de>
129+
{
130+
let string = d.deserialize_option(StringVisitor)?;
97131

98-
pub fn deserialize_uint_from_string<'de, D>(d: D) -> Result<u64, D::Error>
99-
where D: serde::Deserializer<'de>
100-
{
101-
let string = d.deserialize_option(StringVisitor)?;
132+
if "null" == string {
133+
return Ok(0);
134+
}
102135

103-
if "null" == string {
104-
return Ok(0);
105-
}
136+
if !string.starts_with("0x") {
137+
return Err(D::Error::custom(format!("Number parsing error: number must be prefixed with 0x ({})", string)));
138+
}
106139

107-
if !string.starts_with("0x") {
108-
return Err(D::Error::custom(format!("Number parsing error: number must be prefixed with 0x ({})", string)));
140+
u64::from_str_radix(&string[2..], 16)
141+
.map_err(|err| D::Error::custom(format!("Error parsing number: {}", err)))
109142
}
110143

111-
u64::from_str_radix(&string[2..], 16)
112-
.map_err(|err| D::Error::custom(format!("Error parsing number: {}", err)))
144+
pub fn serialize<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
145+
where S: serde::Serializer
146+
{
147+
serializer.serialize_str(&format!("0x{:x}", value))
148+
}
113149
}
114150

115151
pub fn deserialize_tr_state<'de, D>(d: D) -> Result<TransactionProcessingStatus, D::Error>
@@ -174,17 +210,33 @@ pub fn deserialize_message_type<'de, D>(d: D) -> Result<MessageType, D::Error>
174210
}
175211
}
176212

177-
pub fn deserialize_account_status<'de, D>(d: D) -> Result<AccountStatus, D::Error>
178-
where D: serde::Deserializer<'de>
179-
{
180-
let num = d.deserialize_u8(U8Visitor)?;
213+
pub mod account_status {
214+
use super::*;
181215

182-
match num {
183-
0 => Ok(AccountStatus::AccStateUninit),
184-
1 => Ok(AccountStatus::AccStateActive),
185-
2 => Ok(AccountStatus::AccStateFrozen),
186-
3 => Ok(AccountStatus::AccStateNonexist),
187-
num => Err(D::Error::custom(format!("Invalid account status: {}", num)))
216+
pub fn deserialize<'de, D>(d: D) -> Result<AccountStatus, D::Error>
217+
where D: serde::Deserializer<'de>
218+
{
219+
let num = d.deserialize_u8(U8Visitor)?;
220+
221+
match num {
222+
0 => Ok(AccountStatus::AccStateUninit),
223+
1 => Ok(AccountStatus::AccStateActive),
224+
2 => Ok(AccountStatus::AccStateFrozen),
225+
3 => Ok(AccountStatus::AccStateNonexist),
226+
num => Err(D::Error::custom(format!("Invalid account status: {}", num)))
227+
}
228+
}
229+
230+
pub fn serialize<S>(value: &AccountStatus, serializer: S) -> Result<S::Ok, S::Error>
231+
where S: serde::Serializer
232+
{
233+
serializer.serialize_u8(
234+
match value {
235+
AccountStatus::AccStateUninit => 0,
236+
AccountStatus::AccStateActive => 1,
237+
AccountStatus::AccStateFrozen => 2,
238+
AccountStatus::AccStateNonexist => 3
239+
})
188240
}
189241
}
190242

ton_sdk/src/local_tvm.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,25 +136,15 @@ pub mod executor {
136136
};
137137
use ton_executor::ExecutorError;
138138

139-
#[derive(Default, Debug)]
140-
pub struct TransactionFees {
141-
pub in_msg_fwd_fee: u64,
142-
pub storage_fee: u64,
143-
pub gas_fee: u64,
144-
pub out_msgs_fwd_fee: u64,
145-
pub total_account_fees: u64,
146-
pub total_output: u64,
147-
}
148-
149139
pub(crate) fn call_executor(account: Account, msg: Message, config: BlockchainConfig, timestamp: u32)
150-
-> Result<Transaction>
140+
-> Result<(Transaction, Cell)>
151141
{
152142
let mut acc_root = account.write_to_new_cell()?.into();
153143

154144
let block_lt = 1_000_000;
155145
let lt = Arc::new(std::sync::atomic::AtomicU64::new(block_lt + 1));
156146
let executor = OrdinaryTransactionExecutor::new(config);
157-
executor.execute(
147+
let transaction = executor.execute(
158148
Some(&msg),
159149
&mut acc_root,
160150
timestamp,
@@ -167,7 +157,8 @@ pub mod executor {
167157
Some(ExecutorError::NoFundsToImportMsg) => SdkError::NoFundsError.into(),
168158
_ => err
169159
}
170-
})
160+
})?;
161+
Ok((transaction, acc_root))
171162
}
172163
}
173164

0 commit comments

Comments
 (0)