Skip to content

Commit 8ca427d

Browse files
committed
feat(soroban): update build_solidity to accept env conf functions
1 parent c7c1008 commit 8ca427d

File tree

9 files changed

+131
-135
lines changed

9 files changed

+131
-135
lines changed

src/codegen/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ impl From<inkwell::OptimizationLevel> for OptimizationLevel {
9797
pub enum HostFunctions {
9898
PutContractData,
9999
GetContractData,
100+
ExtendContractDataTtl,
100101
LogFromLinearMemory,
101102
SymbolNewFromLinearMemory,
102103
VectorNew,
@@ -111,6 +112,7 @@ impl HostFunctions {
111112
match self {
112113
HostFunctions::PutContractData => "l._",
113114
HostFunctions::GetContractData => "l.1",
115+
HostFunctions::ExtendContractDataTtl => "l.7",
114116
HostFunctions::LogFromLinearMemory => "x._",
115117
HostFunctions::SymbolNewFromLinearMemory => "b.j",
116118
HostFunctions::VectorNew => "v._",

src/emit/soroban/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ impl HostFunctions {
3939
.context
4040
.i64_type()
4141
.fn_type(&[ty.into(), ty.into()], false),
42+
// https://github.com/stellar/stellar-protocol/blob/2fdc77302715bc4a31a784aef1a797d466965024/core/cap-0046-03.md#ledger-host-functions-mod-l
43+
// ;; If the entry's TTL is below `threshold` ledgers, extend `live_until_ledger_seq` such that TTL == `extend_to`, where TTL is defined as live_until_ledger_seq - current ledger.
44+
// (func $extend_contract_data_ttl (param $k_val i64) (param $t_storage_type i64) (param $threshold_u32_val i64) (param $extend_to_u32_val i64) (result i64))
45+
HostFunctions::ExtendContractDataTtl => bin
46+
.context
47+
.i64_type()
48+
.fn_type(&[ty.into(), ty.into(), ty.into(), ty.into()], false),
4249
HostFunctions::LogFromLinearMemory => bin
4350
.context
4451
.i64_type()
@@ -279,6 +286,7 @@ impl SorobanTarget {
279286
let host_functions = [
280287
HostFunctions::PutContractData,
281288
HostFunctions::GetContractData,
289+
HostFunctions::ExtendContractDataTtl,
282290
HostFunctions::LogFromLinearMemory,
283291
HostFunctions::SymbolNewFromLinearMemory,
284292
HostFunctions::VectorNew,

src/emit/soroban/target.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ use inkwell::values::{
1717
ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue,
1818
PointerValue,
1919
};
20-
use num_traits::ToPrimitive;
2120

2221
use solang_parser::pt::{Loc, StorageType};
2322

23+
use num_traits::ToPrimitive;
24+
2425
use std::collections::HashMap;
2526

2627
// TODO: Implement TargetRuntime for SorobanTarget.
@@ -509,7 +510,8 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
509510
let extend_to_u32_val = (extend_to << 32) + 4;
510511

511512
// Call the function
512-
let function_value = bin.module.get_function(EXTEND_CONTRACT_DATA_TTL).unwrap();
513+
let function_name = HostFunctions::ExtendContractDataTtl.name();
514+
let function_value = bin.module.get_function(function_name).unwrap();
513515

514516
let value = bin
515517
.builder
@@ -527,7 +529,7 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
527529
.const_int(extend_to_u32_val, false)
528530
.into(),
529531
],
530-
EXTEND_CONTRACT_DATA_TTL,
532+
function_name,
531533
)
532534
.unwrap()
533535
.try_as_basic_value()

tests/soroban.rs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,16 @@ pub struct SorobanEnv {
1919
compiler_diagnostics: Diagnostics,
2020
}
2121

22-
pub fn build_solidity(src: &str) -> SorobanEnv {
22+
pub fn build_solidity<F>(src: &str, configure_env: F) -> SorobanEnv
23+
where
24+
F: FnOnce(&mut SorobanEnv),
25+
{
2326
let (wasm_blob, ns) = build_wasm(src);
24-
SorobanEnv::new_with_contract(wasm_blob).insert_diagnostics(ns.diagnostics)
27+
28+
let env =
29+
SorobanEnv::new_with_contract(wasm_blob, configure_env).insert_diagnostics(ns.diagnostics);
30+
31+
env
2532
}
2633

2734
fn build_wasm(src: &str) -> (Vec<u8>, Namespace) {
@@ -51,7 +58,6 @@ fn build_wasm(src: &str) -> (Vec<u8>, Namespace) {
5158
}
5259

5360
impl SorobanEnv {
54-
/// Create a new Soroban environment
5561
pub fn new() -> Self {
5662
Self {
5763
env: Env::default(),
@@ -65,31 +71,29 @@ impl SorobanEnv {
6571
self
6672
}
6773

68-
/// Create a new Soroban environment with a contract
69-
pub fn new_with_contract(
70-
contract_wasm: Vec<u8>,
71-
constructor_args: soroban_sdk::Vec<Val>,
72-
) -> Self {
74+
pub fn new_with_contract<F>(contract_wasm: Vec<u8>, configure_env: F) -> Self
75+
where
76+
F: FnOnce(&mut SorobanEnv),
77+
{
7378
let mut env = Self::new();
74-
env.register_contract(contract_wasm, constructor_args);
79+
configure_env(&mut env);
80+
81+
env.register_contract(contract_wasm);
82+
7583
env
7684
}
7785

78-
/// Register a contract given its WASM blob and constructor arguments
79-
pub fn register_contract(
80-
&mut self,
81-
contract_wasm: Vec<u8>,
82-
constructor_args: soroban_sdk::Vec<Val>,
83-
) -> Address {
86+
pub fn register_contract(&mut self, contract_wasm: Vec<u8>) -> Address {
87+
// For now, we keep using `register_contract_wasm`. To use `register`, we have to figure
88+
// out first what to pass for `constructor_args`
89+
#[allow(deprecated)]
8490
let addr = self
8591
.env
86-
.register(contract_wasm.as_slice(), constructor_args);
87-
92+
.register_contract_wasm(None, contract_wasm.as_slice());
8893
self.contracts.push(addr.clone());
8994
addr
9095
}
9196

92-
/// Invoke a contract and return the result
9397
pub fn invoke_contract(&self, addr: &Address, function_name: &str, args: Vec<Val>) -> Val {
9498
let func = Symbol::new(&self.env, function_name);
9599
let mut args_soroban = vec![&self.env];

tests/soroban_testcases/cross_contract_calls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn simple_cross_contract() {
1515
}
1616
}
1717
}"#,
18+
|_| {},
1819
);
1920

2021
let caller = runtime.deploy_contract(

tests/soroban_testcases/math.rs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
use crate::{build_solidity, SorobanEnv};
3+
use crate::build_solidity;
44
use soroban_sdk::{IntoVal, Val};
55

66
#[test]
77
fn math() {
8-
let wasm = build_solidity(
8+
let runtime = build_solidity(
99
r#"contract math {
1010
function max(uint64 a, uint64 b) public returns (uint64) {
1111
if (a > b) {
@@ -15,25 +15,22 @@ fn math() {
1515
}
1616
}
1717
}"#,
18+
|_| {},
1819
);
1920

20-
let mut runtime = SorobanEnv::new();
21-
// No constructor arguments
22-
let constructor_args: soroban_sdk::Vec<Val> = soroban_sdk::Vec::new(&runtime.env);
23-
let addr = runtime.register_contract(wasm, constructor_args);
24-
2521
let arg: Val = 5_u64.into_val(&runtime.env);
2622
let arg2: Val = 4_u64.into_val(&runtime.env);
2723

28-
let res = runtime.invoke_contract(&addr, "max", vec![arg, arg2]);
24+
let addr = runtime.contracts.last().unwrap();
25+
let res = runtime.invoke_contract(addr, "max", vec![arg, arg2]);
2926

3027
let expected: Val = 5_u64.into_val(&runtime.env);
3128
assert!(expected.shallow_eq(&res));
3229
}
3330

3431
#[test]
3532
fn math_same_name() {
36-
let wasm = build_solidity(
33+
let src = build_solidity(
3734
r#"contract math {
3835
function max(uint64 a, uint64 b) public returns (uint64) {
3936
if (a > b) {
@@ -60,23 +57,21 @@ fn math_same_name() {
6057
}
6158
}
6259
"#,
60+
|_| {},
6361
);
6462

65-
let mut runtime = SorobanEnv::new();
66-
// No constructor arguments
67-
let constructor_args: soroban_sdk::Vec<Val> = soroban_sdk::Vec::new(&runtime.env);
68-
let addr = runtime.register_contract(wasm, constructor_args);
63+
let addr = src.contracts.last().unwrap();
6964

70-
let arg1: Val = 5_u64.into_val(&runtime.env);
71-
let arg2: Val = 4_u64.into_val(&runtime.env);
72-
let res = runtime.invoke_contract(&addr, "max_uint64_uint64", vec![arg1, arg2]);
73-
let expected: Val = 5_u64.into_val(&runtime.env);
65+
let arg1: Val = 5_u64.into_val(&src.env);
66+
let arg2: Val = 4_u64.into_val(&src.env);
67+
let res = src.invoke_contract(addr, "max_uint64_uint64", vec![arg1, arg2]);
68+
let expected: Val = 5_u64.into_val(&src.env);
7469
assert!(expected.shallow_eq(&res));
7570

76-
let arg1: Val = 5_u64.into_val(&runtime.env);
77-
let arg2: Val = 4_u64.into_val(&runtime.env);
78-
let arg3: Val = 6_u64.into_val(&runtime.env);
79-
let res = runtime.invoke_contract(&addr, "max_uint64_uint64_uint64", vec![arg1, arg2, arg3]);
80-
let expected: Val = 6_u64.into_val(&runtime.env);
71+
let arg1: Val = 5_u64.into_val(&src.env);
72+
let arg2: Val = 4_u64.into_val(&src.env);
73+
let arg3: Val = 6_u64.into_val(&src.env);
74+
let res = src.invoke_contract(addr, "max_uint64_uint64_uint64", vec![arg1, arg2, arg3]);
75+
let expected: Val = 6_u64.into_val(&src.env);
8176
assert!(expected.shallow_eq(&res));
8277
}

tests/soroban_testcases/print.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
use crate::{build_solidity, SorobanEnv};
4-
use soroban_sdk::{testutils::Logs, Val};
3+
use crate::build_solidity;
4+
use soroban_sdk::testutils::Logs;
55

66
#[test]
77
fn log_runtime_error() {
8-
let wasm = build_solidity(
8+
let src = build_solidity(
99
r#"contract counter {
1010
uint64 public count = 1;
1111
@@ -14,46 +14,42 @@ fn log_runtime_error() {
1414
return count;
1515
}
1616
}"#,
17+
|_| {},
1718
);
1819

19-
let mut runtime = SorobanEnv::new();
20-
// No constructor arguments
21-
let constructor_args: soroban_sdk::Vec<Val> = soroban_sdk::Vec::new(&runtime.env);
22-
let addr = runtime.register_contract(wasm, constructor_args);
20+
let addr = src.contracts.last().unwrap();
2321

24-
runtime.invoke_contract(&addr, "decrement", vec![]);
22+
src.invoke_contract(addr, "decrement", vec![]);
2523

26-
let logs = runtime.invoke_contract_expect_error(&addr, "decrement", vec![]);
24+
let logs = src.invoke_contract_expect_error(addr, "decrement", vec![]);
2725

2826
assert!(logs[0].contains("runtime_error: math overflow in test.sol:5:17-27"));
2927
}
3028

3129
#[test]
3230
fn print() {
33-
let wasm = build_solidity(
31+
let src = build_solidity(
3432
r#"contract Printer {
3533
3634
function print() public {
3735
print("Hello, World!");
3836
}
3937
}"#,
38+
|_| {},
4039
);
4140

42-
let mut runtime = SorobanEnv::new();
43-
// No constructor arguments
44-
let constructor_args: soroban_sdk::Vec<Val> = soroban_sdk::Vec::new(&runtime.env);
45-
let addr = runtime.register_contract(wasm, constructor_args);
41+
let addr = src.contracts.last().unwrap();
4642

47-
runtime.invoke_contract(&addr, "print", vec![]);
43+
src.invoke_contract(addr, "print", vec![]);
4844

49-
let logs = runtime.env.logs().all();
45+
let logs = src.env.logs().all();
5046

5147
assert!(logs[0].contains("Hello, World!"));
5248
}
5349

5450
#[test]
5551
fn print_then_runtime_error() {
56-
let wasm = build_solidity(
52+
let src = build_solidity(
5753
r#"contract counter {
5854
uint64 public count = 1;
5955
@@ -63,16 +59,14 @@ fn print_then_runtime_error() {
6359
return count;
6460
}
6561
}"#,
62+
|_| {},
6663
);
6764

68-
let mut runtime = SorobanEnv::new();
69-
// No constructor arguments
70-
let constructor_args: soroban_sdk::Vec<Val> = soroban_sdk::Vec::new(&runtime.env);
71-
let addr = runtime.register_contract(wasm, constructor_args);
65+
let addr = src.contracts.last().unwrap();
7266

73-
runtime.invoke_contract(&addr, "decrement", vec![]);
67+
src.invoke_contract(addr, "decrement", vec![]);
7468

75-
let logs = runtime.invoke_contract_expect_error(&addr, "decrement", vec![]);
69+
let logs = src.invoke_contract_expect_error(addr, "decrement", vec![]);
7670

7771
assert!(logs[0].contains("Second call will FAIL!"));
7872
assert!(logs[1].contains("runtime_error: math overflow in test.sol:6:17-27"));

0 commit comments

Comments
 (0)