Skip to content

Commit f03ae3d

Browse files
committed
add missing library request
1 parent 60faf96 commit f03ae3d

File tree

12 files changed

+148
-10
lines changed

12 files changed

+148
-10
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ nekoton-transport = { path = "./transport" }
4848
nekoton-utils = { path = "./utils" }
4949
nekoton-proc = { path = "./proc" }
5050

51-
#[patch.crates-io]
51+
[patch.crates-io]
52+
tycho-executor = { git = "https://github.com/broxus/tycho-vm.git", branch = "feature/missing-libraries"}
53+
tycho-vm = { git = "https://github.com/broxus/tycho-vm.git", branch = "feature/missing-libraries" }
54+
tycho-types = { git = "https://github.com/broxus/tycho-types.git", branch = "feature/missing-libraries" }
55+
5256
#everscale-types = { git = "https://github.com/broxus/everscale-types.git" }
5357

core/src/contracts/blockchain_context.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use nekoton_utils::time::{Clock, SimpleClock};
77
use num_bigint::BigInt;
88
use tycho_executor::ExecutorParams;
99
use tycho_types::abi::{Function, NamedAbiValue};
10+
use tycho_types::cell::HashBytes;
1011
use tycho_types::crc::crc_16;
1112
use tycho_types::models::{
12-
Account, BlockchainConfig, ExtInMsgInfo, IntAddr, IntMsgInfo, MsgInfo, OwnedMessage, StdAddr,
13-
Transaction,
13+
Account, BlockchainConfig, ExtInMsgInfo, IntAddr, IntMsgInfo, LibDescr, MsgInfo, OwnedMessage,
14+
StdAddr, Transaction,
1415
};
1516
use tycho_types::prelude::{Cell, CellBuilder, CellFamily, DynCell};
1617
use tycho_vm::{BehaviourModifiers, OwnedCellSlice, RcStackValue, SafeRc};
@@ -145,6 +146,16 @@ impl BlockchainAccount {
145146

146147
local_vm.call_getter(gen_utime, gen_lt, &self.account, stack_values)
147148
}
149+
pub fn add_library(&mut self, library: HashBytes, cell: Cell) -> Result<(), ExecutionError> {
150+
self.context.desc.executor_params.libraries.set(
151+
library,
152+
LibDescr {
153+
lib: cell,
154+
publishers: Default::default(),
155+
},
156+
)?;
157+
Ok(())
158+
}
148159
}
149160

150161
pub struct BlockchainContextBuilder {

core/src/contracts/function_ext.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use num_traits::cast::ToPrimitive;
22
use tycho_executor::ParsedConfig;
33
use tycho_types::abi::{AbiType, AbiValue, Function, NamedAbiValue};
4+
use tycho_types::cell::HashBytes;
45
use tycho_types::models::{Account, RelaxedMsgInfo};
56
use tycho_types::num::Tokens;
67
use tycho_vm::OwnedCellSlice;
@@ -79,6 +80,7 @@ impl FunctionExt for Function {
7980
return Ok(ExecutionOutput {
8081
values: vec![],
8182
exit_code: !compute_phase_result.exit_code,
83+
missing_library: compute_phase_result.missing_library,
8284
});
8385
}
8486

@@ -130,6 +132,7 @@ impl FunctionExt for Function {
130132
Ok(ExecutionOutput {
131133
values: output,
132134
exit_code: !compute_phase_result.exit_code,
135+
missing_library: compute_phase_result.missing_library,
133136
})
134137
}
135138
}
@@ -138,4 +141,5 @@ impl FunctionExt for Function {
138141
pub struct ExecutionOutput {
139142
pub values: Vec<NamedAbiValue>,
140143
pub exit_code: i32,
144+
pub missing_library: Option<HashBytes>,
141145
}

core/src/contracts/local_executor.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use tycho_types::cell::{Cell, CellBuilder};
1+
use tycho_types::cell::{Cell, CellBuilder, HashBytes};
22
use tycho_types::models::{
33
Account, ComputePhase, IntAddr, MsgType, OutAction, OutActionsRevIter, OwnedMessage,
44
OwnedRelaxedMessage, ShardAccount, Transaction,
@@ -16,6 +16,7 @@ pub struct ComputePhaseResult {
1616
pub exit_code: i32,
1717
pub success: bool,
1818
pub out_messages: Vec<OwnedRelaxedMessage>,
19+
pub missing_library: Option<HashBytes>,
1920
}
2021
#[allow(clippy::too_many_arguments)]
2122
pub fn execute_message(
@@ -66,6 +67,7 @@ pub fn execute_message(
6667
exit_code: !executed_compute_phase.exit_code,
6768
success: executed_compute_phase.success,
6869
out_messages: msgs,
70+
missing_library: executed_compute_phase.missing_library,
6971
})
7072
}
7173

core/src/transport.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::models::{ContractState, LastTransactionId, LatestBlockchainConfig};
33
use nekoton_utils::time::{Clock, SimpleClock, Timings};
44
use std::collections::HashMap;
55
use tycho_executor::{ExecutorParams, ParsedConfig};
6-
use tycho_types::cell::HashBytes;
6+
use tycho_types::cell::{Cell, HashBytes};
77
use tycho_types::models::{
88
BlockchainConfig, MsgInfo, OwnedMessage, ShardAccount, StdAddr, Transaction,
99
};
@@ -19,6 +19,7 @@ pub trait Transport: Send + Sync {
1919
) -> anyhow::Result<ContractState>;
2020
async fn get_config(&self) -> anyhow::Result<LatestBlockchainConfig>;
2121
async fn get_transaction(&self, hash: &HashBytes) -> anyhow::Result<Option<Transaction>>;
22+
async fn get_library_cell(&self, hash: &HashBytes) -> anyhow::Result<Option<Cell>>;
2223
async fn get_dst_transaction(
2324
&self,
2425
message_hash: &HashBytes,
@@ -137,6 +138,9 @@ impl Transport for SimpleTransport {
137138
async fn get_transaction(&self, _: &HashBytes) -> anyhow::Result<Option<Transaction>> {
138139
todo!()
139140
}
141+
async fn get_library_cell(&self, _: &HashBytes) -> anyhow::Result<Option<Cell>> {
142+
todo!()
143+
}
140144

141145
async fn get_dst_transaction(&self, _: &HashBytes) -> anyhow::Result<Option<Transaction>> {
142146
todo!()

proc/src/generator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,13 @@ impl StructGenerator {
220220
} else {
221221
format!("{}FunctionInput", name.to_camel())
222222
};
223-
223+
224224
let struct_name = if name.starts_with("_") {
225225
format!("{f_name}Ext")
226226
} else {
227227
f_name
228228
};
229-
229+
230230
let model = self.generate_model(&struct_name, inputs.clone());
231231

232232
if !self.generated_structs.contains_key(&struct_name) {

proc/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use std::fs;
66
use std::path::Path;
77
use syn::parse::{Parse, ParseStream};
88
use syn::{parse_macro_input, ItemMod};
9-
use tycho_types::abi::{AbiHeaderType, Contract};
109
use syn::{LitStr, Result};
10+
use tycho_types::abi::{AbiHeaderType, Contract};
1111

1212
use crate::generator::{FunctionDescriptionTokens, StructGenerator};
1313

transport/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ async-trait = { workspace = true }
1414
tycho-types = { workspace = true }
1515
futures-util = { workspace = true }
1616
parking_lot = { workspace = true }
17+
num-bigint = {workspace = true}
18+
num-traits = {workspace = true}
1719
#proof-api-util = { workspace = true }
1820
rand = { workspace = true }
1921
reqwest = { workspace = true, features = ["gzip", "http2", "json", "rustls-tls"] }

transport/src/lib.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@ pub mod rpc;
44
#[cfg(test)]
55
pub mod tests {
66
use crate::rpc::RpcTransport;
7+
use core::panic;
78
use futures_util::StreamExt;
9+
use nekoton_core::contracts::blockchain_context::BlockchainContextBuilder;
810
use nekoton_core::transactions::TraceTransaction;
11+
use nekoton_core::transport::{SimpleTransport, Transport};
12+
use num_bigint::BigUint;
13+
use num_traits::Zero;
914
use reqwest::Url;
1015
use std::str::FromStr;
1116
use std::sync::Arc;
17+
use tycho_types::abi::{AbiHeaderType, AbiType, AbiValue, AbiVersion, Function};
18+
use tycho_types::boc::Boc;
1219
use tycho_types::cell::HashBytes;
20+
use tycho_types::models::BlockchainConfig;
1321

1422
#[tokio::test]
1523
async fn traced_tx() {
@@ -28,4 +36,68 @@ pub mod tests {
2836
}
2937
assert_eq!(counter, 12);
3038
}
39+
40+
#[tokio::test]
41+
async fn get_state_with_retries_for_libraries() {
42+
let config_cell = Boc::decode_base64("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").unwrap();
43+
let config = config_cell.parse::<BlockchainConfig>().unwrap();
44+
45+
let account_cell = Boc::decode_base64("te6ccgEBBAEA3wACboARPmKFmZb7UI1FgPY5MbJYJKPzmu4RUDN9k8WayPe7kGQRAqUGil+P0AAAT3BmG1o6AvrwgCYDAQGTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAIurEomVjZY/EfuvEyNXOvBmybt5bgpnmtwgyymLnInvgCAGOACOx2tye/5lfR4Ih+BBGfLQA67cTHekeUzHx9YuGo73UAAAAAAAAAAAAAAAAAAAABUAhCApZ8lwbZVdfn7LyATToKdb89MzDWfAhUcDRsBzsioiQS").unwrap();
46+
47+
let inputs = vec![AbiType::Uint(32).named("answerId")];
48+
49+
let outputs = vec![AbiType::Uint(128).named("value0")];
50+
51+
let headers = vec![
52+
AbiHeaderType::PublicKey,
53+
AbiHeaderType::Time,
54+
AbiHeaderType::Expire,
55+
];
56+
let function = Function::builder(AbiVersion::V2_3, "balance")
57+
.with_headers(headers)
58+
.with_inputs(inputs)
59+
.with_outputs(outputs)
60+
.build();
61+
62+
let transport = SimpleTransport::new(vec![], config.clone()).unwrap();
63+
64+
let context = BlockchainContextBuilder::new()
65+
.with_config(config)
66+
.with_transport(Arc::new(transport))
67+
.build()
68+
.unwrap();
69+
70+
let mut account = context
71+
.get_account_from_cell(account_cell.as_ref())
72+
.unwrap();
73+
74+
let values = vec![AbiValue::Uint(32, BigUint::zero()).named("answerId")];
75+
76+
let urls = vec![Url::from_str("https://rpc-testnet.tychoprotocol.com/").unwrap()];
77+
let rpc_transport = RpcTransport::new(urls, Default::default(), false)
78+
.await
79+
.unwrap();
80+
81+
loop {
82+
match account.run_local(&function, values.as_slice()) {
83+
Ok(output) if output.exit_code == 1 || output.exit_code == 0 => (),
84+
Ok(output) => {
85+
println!("output: {output:?}");
86+
if let Some(missing_library) = output.missing_library {
87+
if let Some(library_cell) = rpc_transport
88+
.get_library_cell(&missing_library)
89+
.await
90+
.unwrap()
91+
{
92+
account.add_library(missing_library, library_cell).unwrap();
93+
} else {
94+
panic!("library not found");
95+
}
96+
}
97+
panic!("unexpected exit code: {}", output.exit_code);
98+
}
99+
Err(e) => panic!("error: {e:?}"),
100+
}
101+
}
102+
}
31103
}

transport/src/rpc/jrpc_client.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,33 @@ impl JrpcClient {
154154
}
155155
}
156156
}
157+
158+
pub async fn get_library_cell(&self, hash: &HashBytes) -> Result<Option<Cell>> {
159+
#[derive(Serialize)]
160+
struct Params<'a> {
161+
#[serde(default, with = "serde_hex_array")]
162+
id: &'a HashBytes,
163+
}
164+
let params = JrpcRequest {
165+
method: "getLibraryCell",
166+
params: &Params { id: hash },
167+
};
168+
169+
#[derive(Deserialize)]
170+
struct LibraryCellResponse {
171+
cell: Option<String>,
172+
}
173+
174+
let res = self.post::<_, LibraryCellResponse>(&params).await?;
175+
176+
match res.cell {
177+
None => Ok(None),
178+
Some(cell) => {
179+
let lib = BocRepr::decode_base64(cell)?;
180+
Ok(Some(lib))
181+
}
182+
}
183+
}
157184
}
158185

159186
struct JrpcRequest<'a, T> {

0 commit comments

Comments
 (0)