Skip to content

Commit c7bbceb

Browse files
committed
Add support for all but the math_* milestone 3 imports
1 parent 1e2ffe1 commit c7bbceb

File tree

10 files changed

+309
-4
lines changed

10 files changed

+309
-4
lines changed

integration/stylus/milestone_3.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity >=0.8.0;
3+
4+
contract C {
5+
function test() public view returns (uint256, bytes32, bytes32, uint256) {
6+
bytes memory code = address(this).code;
7+
8+
uint256 balance = address(this).balance;
9+
bytes32 codehash = address(this).codehash;
10+
bytes32 manual_codehash = keccak256(code);
11+
uint256 gasprice = tx.gasprice;
12+
13+
print("balance = {}".format(balance));
14+
print("codehash = {}".format(codehash));
15+
print("manual_codehash = {}".format(manual_codehash));
16+
print("gasprice = {}".format(gasprice));
17+
18+
assert(codehash == manual_codehash);
19+
20+
return (balance, codehash, manual_codehash, gasprice);
21+
}
22+
23+
function getCode() public view returns (bytes) {
24+
return address(this).code;
25+
}
26+
27+
function accept_donation() public payable {}
28+
}

src/codegen/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,7 @@ pub enum Builtin {
18071807
Calldata,
18081808
ChainId,
18091809
ContractCode,
1810+
ContractCodehash,
18101811
Gasleft,
18111812
GasLimit,
18121813
Gasprice,
@@ -1910,6 +1911,7 @@ impl From<&ast::Builtin> for Builtin {
19101911
ast::Builtin::BaseFee => Builtin::BaseFee,
19111912
ast::Builtin::PrevRandao => Builtin::PrevRandao,
19121913
ast::Builtin::ContractCode => Builtin::ContractCode,
1914+
ast::Builtin::ContractCodehash => Builtin::ContractCodehash,
19131915
ast::Builtin::StringConcat | ast::Builtin::BytesConcat => Builtin::Concat,
19141916
ast::Builtin::RequireAuth => Builtin::RequireAuth,
19151917
ast::Builtin::AuthAsCurrContract => Builtin::AuthAsCurrContract,

src/emit/stylus/mod.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ impl StylusTarget {
8686
target.emit_dispatch(&mut bin);
8787

8888
bin.internalize(&[
89+
"account_balance",
90+
"account_code",
91+
"account_code_size",
92+
"account_codehash",
8993
"block_basefee",
9094
"block_coinbase",
9195
"block_gas_limit",
@@ -99,6 +103,11 @@ impl StylusTarget {
99103
"delegate_call_contract",
100104
"emit_log",
101105
"evm_gas_left",
106+
"math_div",
107+
"math_mod",
108+
"math_pow",
109+
"math_add_mod",
110+
"math_mul_mod",
102111
"log_txt",
103112
"msg_reentrant",
104113
"msg_sender",
@@ -114,6 +123,7 @@ impl StylusTarget {
114123
"storage_load_bytes32",
115124
"transient_store_bytes32",
116125
"transient_load_bytes32",
126+
"tx_gas_price",
117127
"tx_origin",
118128
"write_result",
119129
]);
@@ -171,6 +181,10 @@ impl StylusTarget {
171181
};
172182
}
173183

184+
external!("account_balance", void_type, u8_ptr, u8_ptr);
185+
external!("account_code", i32_type, u8_ptr, u32_val, u32_val, u8_ptr);
186+
external!("account_code_size", i32_type, u8_ptr);
187+
external!("account_codehash", void_type, u8_ptr, u8_ptr);
174188
external!("block_basefee", void_type, u8_ptr);
175189
external!("block_coinbase", void_type, u8_ptr);
176190
external!("block_gas_limit", i64_type);
@@ -203,6 +217,11 @@ impl StylusTarget {
203217
external!("evm_gas_left", i64_type);
204218
external!("log_txt", void_type, u8_ptr, u32_val);
205219
external!("msg_reentrant", i32_type);
220+
external!("math_add_mod", void_type, u8_ptr, u8_ptr, u8_ptr);
221+
external!("math_div", void_type, u8_ptr, u8_ptr);
222+
external!("math_mod", void_type, u8_ptr, u8_ptr);
223+
external!("math_mul_mod", void_type, u8_ptr, u8_ptr);
224+
external!("math_pow", void_type, u8_ptr, u8_ptr);
206225
external!("msg_sender", void_type, u8_ptr);
207226
external!("msg_value", void_type, u8_ptr);
208227
external!("native_keccak256", void_type, u8_ptr, u32_val, u8_ptr);
@@ -224,6 +243,7 @@ impl StylusTarget {
224243
external!("storage_load_bytes32", void_type, u8_ptr, u8_ptr);
225244
external!("transient_store_bytes32", void_type, u8_ptr, u8_ptr);
226245
external!("transient_load_bytes32", void_type, u8_ptr, u8_ptr);
246+
external!("tx_gas_price", void_type, u8_ptr);
227247
external!("tx_origin", void_type, u8_ptr);
228248
external!("write_result", void_type, u8_ptr, u32_val);
229249
}

src/emit/stylus/target.rs

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::codegen::{Builtin, Expression};
88
use crate::emit::binary::Binary;
99
use crate::emit::storage::StorageSlot;
1010
use crate::emit::stylus::StylusTarget;
11-
use crate::emit::{ContractArgs, TargetRuntime, Variable};
11+
use crate::emit::{expression::expression, ContractArgs, TargetRuntime, Variable};
1212
use crate::emit_context;
1313
use crate::sema::ast::{self, CallTy};
1414
use crate::sema::ast::{Function, Type};
@@ -895,6 +895,47 @@ impl<'a> TargetRuntime<'a> for StylusTarget {
895895
emit_context!(bin);
896896

897897
match expr {
898+
Expression::Builtin {
899+
kind: Builtin::Balance,
900+
args,
901+
..
902+
} => {
903+
let address = expression(self, bin, &args[0], vartab, function).into_array_value();
904+
905+
let address_ptr = bin
906+
.builder
907+
.build_alloca(bin.address_type(), "address")
908+
.unwrap();
909+
910+
bin.builder.build_store(address_ptr, address).unwrap();
911+
912+
let balance = bin
913+
.builder
914+
.build_alloca(bin.value_type(), "balance")
915+
.unwrap();
916+
917+
call!(
918+
"account_balance",
919+
&[address_ptr.into(), balance.into()],
920+
"account_balance"
921+
);
922+
923+
// smoelius: Balance is big-endian and must be byte-swapped.
924+
let temp = bin.builder.build_alloca(bin.value_type(), "hash").unwrap();
925+
926+
call!(
927+
"__beNtoleN",
928+
&[
929+
balance.into(),
930+
temp.into(),
931+
i32_const!(bin.ns.value_length as u64).into()
932+
]
933+
);
934+
935+
bin.builder
936+
.build_load(bin.value_type(), temp, "balance")
937+
.unwrap()
938+
}
898939
Expression::Builtin {
899940
kind: Builtin::BaseFee,
900941
..
@@ -951,6 +992,90 @@ impl<'a> TargetRuntime<'a> for StylusTarget {
951992

952993
chainid.into()
953994
}
995+
Expression::Builtin {
996+
kind: Builtin::ContractCode,
997+
args,
998+
..
999+
} => {
1000+
let address = expression(self, bin, &args[0], vartab, function).into_array_value();
1001+
1002+
let address_ptr = bin
1003+
.builder
1004+
.build_alloca(bin.address_type(), "address")
1005+
.unwrap();
1006+
1007+
bin.builder.build_store(address_ptr, address).unwrap();
1008+
1009+
let size = call!(
1010+
"account_code_size",
1011+
&[address_ptr.into()],
1012+
"account_code_size"
1013+
)
1014+
.try_as_basic_value()
1015+
.left()
1016+
.unwrap()
1017+
.into_int_value();
1018+
1019+
let account_code = bin
1020+
.builder
1021+
.build_array_alloca(bin.context.i8_type(), size, "account_code")
1022+
.unwrap();
1023+
1024+
call!(
1025+
"account_code",
1026+
&[
1027+
address_ptr.into(),
1028+
i32_zero!().into(),
1029+
size.into(),
1030+
account_code.into(),
1031+
],
1032+
"account_code"
1033+
);
1034+
1035+
call!(
1036+
"vector_new",
1037+
&[size.into(), i32_const!(1).into(), account_code.into()]
1038+
)
1039+
.try_as_basic_value()
1040+
.left()
1041+
.unwrap()
1042+
}
1043+
Expression::Builtin {
1044+
kind: Builtin::ContractCodehash,
1045+
args,
1046+
..
1047+
} => {
1048+
let address = expression(self, bin, &args[0], vartab, function).into_array_value();
1049+
1050+
let address_ptr = bin
1051+
.builder
1052+
.build_alloca(bin.address_type(), "address")
1053+
.unwrap();
1054+
1055+
bin.builder.build_store(address_ptr, address).unwrap();
1056+
1057+
let ty = bin.context.custom_width_int_type(256);
1058+
1059+
let digest_ptr = bin.builder.build_alloca(ty, "digest").unwrap();
1060+
1061+
call!(
1062+
"account_codehash",
1063+
&[address_ptr.into(), digest_ptr.into()],
1064+
"account_codehash"
1065+
);
1066+
1067+
call!(
1068+
"vector_new",
1069+
&[
1070+
i32_const!(32).into(),
1071+
i32_const!(1).into(),
1072+
digest_ptr.into()
1073+
]
1074+
)
1075+
.try_as_basic_value()
1076+
.left()
1077+
.unwrap()
1078+
}
9541079
Expression::Builtin {
9551080
kind: Builtin::Gasleft,
9561081
..
@@ -1020,6 +1145,33 @@ impl<'a> TargetRuntime<'a> for StylusTarget {
10201145
call!("__memcpy", &[dest.into(), args.into(), args_len.into()]);
10211146
v
10221147
}
1148+
Expression::Builtin {
1149+
kind: Builtin::Gasprice,
1150+
..
1151+
} => {
1152+
let gasprice = bin
1153+
.builder
1154+
.build_alloca(bin.value_type(), "gasprice")
1155+
.unwrap();
1156+
1157+
call!("tx_gas_price", &[gasprice.into()], "tx_gas_price");
1158+
1159+
// smoelius: `gasprice` is big-endian and must be byte-swapped.
1160+
let temp = bin.builder.build_alloca(bin.value_type(), "hash").unwrap();
1161+
1162+
call!(
1163+
"__beNtoleN",
1164+
&[
1165+
gasprice.into(),
1166+
temp.into(),
1167+
i32_const!(bin.ns.value_length as u64).into()
1168+
]
1169+
);
1170+
1171+
bin.builder
1172+
.build_load(bin.value_type(), temp, "balance")
1173+
.unwrap()
1174+
}
10231175
Expression::Builtin {
10241176
kind: Builtin::Origin,
10251177
..

src/sema/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,7 @@ pub enum StringLocation<T> {
17531753
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
17541754
pub enum Builtin {
17551755
ContractCode,
1756+
ContractCodehash,
17561757
GetAddress,
17571758
Balance,
17581759
PayableSend,

src/sema/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ pub static BUILTIN_VARIABLE: Lazy<[Prototype; 17]> = Lazy::new(|| {
536536
name: "gasprice",
537537
params: vec![],
538538
ret: vec![Type::Value],
539-
target: vec![Target::default_polkadot(), Target::EVM],
539+
target: vec![Target::default_polkadot(), Target::EVM, Target::Stylus],
540540
doc: "gas price for one gas unit",
541541
constant: false,
542542
},

src/sema/expression/member_access.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ pub(super) fn member_access(
392392
});
393393
}
394394
Type::Address(_) if id.name == "code" => {
395-
if ns.target != Target::EVM {
395+
if ns.target != Target::EVM && ns.target != Target::Stylus {
396396
diagnostics.push(Diagnostic::error(
397397
expr.loc(),
398398
format!("'address.code' is not supported on {}", ns.target),
@@ -407,6 +407,22 @@ pub(super) fn member_access(
407407
args: vec![expr],
408408
});
409409
}
410+
Type::Address(_) if id.name == "codehash" => {
411+
if ns.target != Target::Stylus {
412+
diagnostics.push(Diagnostic::error(
413+
expr.loc(),
414+
format!("'address.codehash' is not supported on {}", ns.target),
415+
));
416+
return Err(());
417+
}
418+
used_variable(ns, &expr, symtable);
419+
return Ok(Expression::Builtin {
420+
loc: *loc,
421+
tys: vec![Type::DynamicBytes],
422+
kind: Builtin::ContractCodehash,
423+
args: vec![expr],
424+
});
425+
}
410426
Type::Contract(ref_contract_no) => {
411427
let mut name_matches = 0;
412428
let mut ext_expr = Err(());

src/sema/mutability.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ fn read_expression(expr: &Expression, state: &mut StateCheck) -> bool {
389389
| Builtin::MinimumBalance
390390
| Builtin::Balance
391391
| Builtin::Accounts
392-
| Builtin::ContractCode,
392+
| Builtin::ContractCode
393+
| Builtin::ContractCodehash,
393394
..
394395
} => state.read(loc),
395396

0 commit comments

Comments
 (0)