Compare commits

..

37 Commits

Author SHA1 Message Date
xermicus ed4508fa9a events fn
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-14 11:00:05 +02:00
xermicus 3eadcb1c40 truncate to xlen fn
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-14 10:59:39 +02:00
xermicus 83bf9d6041 events
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-14 09:46:18 +02:00
xermicus 2194aeebd0 constant values for basefee and difficulty
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-13 18:47:36 +02:00
xermicus 02055c73bb extend mock runtime to allow executing constructors and cross contract calls
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-13 13:50:35 +02:00
xermicus 0e90317488 add contract name to integration to integration test cases
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-10 13:47:47 +02:00
xermicus 03a1918993 parallelize tests
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-10 10:54:01 +02:00
xermicus 5f5ec1a539 simplify wrapped divisions and sdiv cfg
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-10 10:16:40 +02:00
xermicus 6af889c1ff implement division and remainder operations
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-08 23:21:16 +02:00
Cyrill Leutwiler 864e40901f implement address and msg.sender
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-05-08 16:10:48 +02:00
Cyrill Leutwiler ea63991617 implement address and msg.sender
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-05-08 16:09:23 +02:00
Cyrill Leutwiler f80a96059d allow register sized int type for memory offsets
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-05-08 15:55:24 +02:00
xermicus 6f080bb9f4 rename binary to resolc
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-08 11:16:24 +02:00
xermicus e958da5cd1 rename file extensions
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-08 11:02:05 +02:00
xermicus b55669f5c5 remove the zkasm format
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-08 10:48:01 +02:00
Chris 169740eb5e fix: addressed assembly text build mechanism (#9)
Use `build.assembly_text` for `--asm` output
2024-05-08 09:36:17 +02:00
xermicus 95ff85c6d1 implement block.number and block.timestamp
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-07 18:03:17 +02:00
xermicus a7318f2ef6 implement helper for easy allocation of a word on the stack
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-07 13:40:54 +02:00
xermicus c0dd845b39 s/field/word
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-07 13:37:17 +02:00
xermicus 9f8a8a782d 1.78 clippies
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-06 14:34:51 +02:00
xermicus b1a3a452ac internalize register size
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-06 14:30:32 +02:00
xermicus 518c03d045 internalize runtime API function symbols
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-06 13:45:58 +02:00
Chris a75fc55133 feat: use PolkaVM disassembler (#6)
Integrate the PolkaVM disassembler to fix `--asm` output

Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-05-03 12:31:24 +02:00
Chris c547a9ef78 chore: added code formating target (#8)
Makefile: added code formating target

Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-05-03 11:36:07 +02:00
xermicus 336fc63f1d rename target to polkavm
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-02 08:47:44 +02:00
xermicus 9fc24af355 remove usage of llvm memory attributes
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-02 08:34:45 +02:00
Cyrill Leutwiler 85bd888f48 update benchmark results
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-05-01 22:41:28 +02:00
xermicus 426f673b0a use normal style for comments
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-01 16:12:32 +02:00
xermicus 72515254fe rename llvm-context crate
Signed-off-by: xermicus <cyrill@parity.io>
2024-05-01 15:45:09 +02:00
xermicus 9b341853b4 update to polkavm with lazy execution
Signed-off-by: xermicus <cyrill@parity.io>
2024-04-30 15:23:44 +02:00
xermicus 018d9f39fc measure erc20 code size
Signed-off-by: xermicus <cyrill@parity.io>
2024-04-26 15:51:14 +02:00
xermicus 3d44685168 measure flipper code size
Signed-off-by: xermicus <cyrill@parity.io>
2024-04-26 10:51:41 +02:00
xermicus 44ae9e77d5 clippies
Signed-off-by: xermicus <cyrill@parity.io>
2024-04-26 10:39:56 +02:00
xermicus a85d1ef333 prevent confusing AlwaysInline and NoInline on O0
Signed-off-by: xermicus <cyrill@parity.io>
2024-04-26 10:36:28 +02:00
Cyrill Leutwiler 45d53f2ee4 test for codesizes
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-04-25 17:39:49 +02:00
Cyrill Leutwiler 34c233207e add clippy to Makefile
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-04-25 15:10:02 +02:00
Cyrill Leutwiler ec46b211ab extensive benchmark results
Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
2024-04-24 23:19:41 +02:00
233 changed files with 3875 additions and 4541 deletions
Generated
+253 -162
View File
@@ -68,7 +68,7 @@ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
"syn-solidity", "syn-solidity",
"tiny-keccak", "tiny-keccak",
] ]
@@ -92,16 +92,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]] [[package]]
name = "anstyle" name = "anstream"
version = "1.0.6" version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]]
name = "anstyle-parse"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.82" version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
[[package]] [[package]]
name = "ark-ff" name = "ark-ff"
@@ -241,14 +284,14 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.2.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]] [[package]]
name = "base16ct" name = "base16ct"
@@ -351,9 +394,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.95" version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -406,6 +449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive",
] ]
[[package]] [[package]]
@@ -414,8 +458,22 @@ version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [ dependencies = [
"anstream",
"anstyle", "anstyle",
"clap_lex", "clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.63",
] ]
[[package]] [[package]]
@@ -424,6 +482,12 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "colorchoice"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]] [[package]]
name = "colored" name = "colored"
version = "2.1.0" version = "2.1.0"
@@ -672,36 +736,11 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "era-compiler-llvm-context"
version = "1.4.1"
dependencies = [
"anyhow",
"hex",
"inkwell",
"itertools 0.12.1",
"md5",
"num",
"once_cell",
"pallet-contracts-pvm-llapi",
"regex",
"revive-builtins",
"revive-common",
"revive-extensions",
"revive-linker",
"revive-stdlib",
"semver 1.0.22",
"serde",
"sha2",
"sha3",
"zkevm_opcode_defs",
]
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.52.0", "windows-sys 0.52.0",
@@ -756,9 +795,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.0.2" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]] [[package]]
name = "fastrlp" name = "fastrlp"
@@ -818,9 +857,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.14" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -869,9 +908,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.3" version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -888,6 +927,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.9" version = "0.3.9"
@@ -924,6 +969,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "iced-x86"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "impl-codec" name = "impl-codec"
version = "0.6.0" version = "0.6.0"
@@ -969,13 +1023,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.14.3", "hashbrown 0.14.5",
] ]
[[package]] [[package]]
name = "inkwell" name = "inkwell"
version = "0.4.0" version = "0.4.0"
source = "git+https://github.com/TheDan64/inkwell.git#5d5a531c765a6ad37aa6591c0287d0f9109fff62" source = "git+https://github.com/TheDan64/inkwell.git#6c0fb56b3554e939f9ca61b465043d6a84fb7b95"
dependencies = [ dependencies = [
"either", "either",
"inkwell_internals", "inkwell_internals",
@@ -989,11 +1043,11 @@ dependencies = [
[[package]] [[package]]
name = "inkwell_internals" name = "inkwell_internals"
version = "0.9.0" version = "0.9.0"
source = "git+https://github.com/TheDan64/inkwell.git#5d5a531c765a6ad37aa6591c0287d0f9109fff62" source = "git+https://github.com/TheDan64/inkwell.git#6c0fb56b3554e939f9ca61b465043d6a84fb7b95"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
@@ -1007,6 +1061,12 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@@ -1065,9 +1125,9 @@ dependencies = [
[[package]] [[package]]
name = "keccak-asm" name = "keccak-asm"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb8515fff80ed850aea4a1595f2e519c003e2a00a82fe168ebf5269196caf444" checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758"
dependencies = [ dependencies = [
"digest 0.10.7", "digest 0.10.7",
"sha3-asm", "sha3-asm",
@@ -1081,9 +1141,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.154"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
[[package]] [[package]]
name = "libm" name = "libm"
@@ -1126,7 +1186,7 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"regex-lite", "regex-lite",
"semver 1.0.22", "semver 1.0.23",
] ]
[[package]] [[package]]
@@ -1158,9 +1218,9 @@ dependencies = [
[[package]] [[package]]
name = "num" name = "num"
version = "0.4.2" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-complex", "num-complex",
@@ -1172,20 +1232,19 @@ dependencies = [
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.4" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
dependencies = [ dependencies = [
"autocfg",
"num-integer", "num-integer",
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
@@ -1201,9 +1260,9 @@ dependencies = [
[[package]] [[package]]
name = "num-iter" name = "num-iter"
version = "0.1.44" version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"num-integer", "num-integer",
@@ -1212,11 +1271,10 @@ dependencies = [
[[package]] [[package]]
name = "num-rational" name = "num-rational"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [ dependencies = [
"autocfg",
"num-bigint", "num-bigint",
"num-integer", "num-integer",
"num-traits", "num-traits",
@@ -1224,9 +1282,9 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.18" version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"libm", "libm",
@@ -1262,9 +1320,9 @@ dependencies = [
[[package]] [[package]]
name = "parity-scale-codec" name = "parity-scale-codec"
version = "3.6.9" version = "3.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bitvec", "bitvec",
@@ -1276,11 +1334,11 @@ dependencies = [
[[package]] [[package]]
name = "parity-scale-codec-derive" name = "parity-scale-codec-derive"
version = "3.6.9" version = "3.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c"
dependencies = [ dependencies = [
"proc-macro-crate 2.0.2", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
@@ -1288,9 +1346,9 @@ dependencies = [
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.14" version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]] [[package]]
name = "path-slash" name = "path-slash"
@@ -1300,9 +1358,9 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.7.9" version = "2.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8"
dependencies = [ dependencies = [
"memchr", "memchr",
"thiserror", "thiserror",
@@ -1349,8 +1407,8 @@ dependencies = [
[[package]] [[package]]
name = "polkavm" name = "polkavm"
version = "0.9.3" version = "0.10.0"
source = "git+https://github.com/koute/polkavm.git?branch=master_byteswap#8b8050bd58be30c6001925b5b2785bc9c98cca4e" source = "git+https://github.com/koute/polkavm.git?rev=266658b#266658b328975ec07ec389f8d966a894f37a8916"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@@ -1361,27 +1419,39 @@ dependencies = [
[[package]] [[package]]
name = "polkavm-assembler" name = "polkavm-assembler"
version = "0.9.0" version = "0.10.0"
source = "git+https://github.com/koute/polkavm.git?branch=master_byteswap#8b8050bd58be30c6001925b5b2785bc9c98cca4e" source = "git+https://github.com/koute/polkavm.git?rev=266658b#266658b328975ec07ec389f8d966a894f37a8916"
dependencies = [ dependencies = [
"log", "log",
] ]
[[package]] [[package]]
name = "polkavm-common" name = "polkavm-common"
version = "0.9.0" version = "0.10.0"
source = "git+https://github.com/koute/polkavm.git?branch=master_byteswap#8b8050bd58be30c6001925b5b2785bc9c98cca4e" source = "git+https://github.com/koute/polkavm.git?rev=266658b#266658b328975ec07ec389f8d966a894f37a8916"
dependencies = [ dependencies = [
"log", "log",
] ]
[[package]]
name = "polkavm-disassembler"
version = "0.10.0"
source = "git+https://github.com/koute/polkavm.git?rev=266658b#266658b328975ec07ec389f8d966a894f37a8916"
dependencies = [
"clap 4.5.4",
"iced-x86",
"polkavm",
"polkavm-common",
"polkavm-linker",
]
[[package]] [[package]]
name = "polkavm-linker" name = "polkavm-linker"
version = "0.9.2" version = "0.10.0"
source = "git+https://github.com/koute/polkavm.git?branch=master_byteswap#8b8050bd58be30c6001925b5b2785bc9c98cca4e" source = "git+https://github.com/koute/polkavm.git?rev=266658b#266658b328975ec07ec389f8d966a894f37a8916"
dependencies = [ dependencies = [
"gimli", "gimli",
"hashbrown 0.14.3", "hashbrown 0.14.5",
"log", "log",
"object", "object",
"polkavm-common", "polkavm-common",
@@ -1391,8 +1461,8 @@ dependencies = [
[[package]] [[package]]
name = "polkavm-linux-raw" name = "polkavm-linux-raw"
version = "0.9.0" version = "0.10.0"
source = "git+https://github.com/koute/polkavm.git?branch=master_byteswap#8b8050bd58be30c6001925b5b2785bc9c98cca4e" source = "git+https://github.com/koute/polkavm.git?rev=266658b#266658b328975ec07ec389f8d966a894f37a8916"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
@@ -1415,22 +1485,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "1.3.1" version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
dependencies = [ dependencies = [
"once_cell", "toml_edit",
"toml_edit 0.19.15",
]
[[package]]
name = "proc-macro-crate"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
dependencies = [
"toml_datetime",
"toml_edit 0.20.2",
] ]
[[package]] [[package]]
@@ -1459,9 +1518,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.81" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -1653,6 +1712,7 @@ dependencies = [
name = "revive-differential" name = "revive-differential"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"alloy-primitives",
"evm-interpreter", "evm-interpreter",
"primitive-types", "primitive-types",
] ]
@@ -1671,11 +1731,15 @@ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-sol-types", "alloy-sol-types",
"env_logger", "env_logger",
"era-compiler-llvm-context",
"hex", "hex",
"polkavm", "polkavm",
"rayon",
"revive-common",
"revive-differential", "revive-differential",
"revive-llvm-context",
"revive-solidity", "revive-solidity",
"serde",
"serde_json",
"sha1", "sha1",
] ]
@@ -1693,13 +1757,38 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "revive-llvm-context"
version = "1.4.1"
dependencies = [
"anyhow",
"hex",
"inkwell",
"itertools 0.12.1",
"md5",
"num",
"once_cell",
"pallet-contracts-pvm-llapi",
"polkavm-common",
"polkavm-disassembler",
"regex",
"revive-builtins",
"revive-common",
"revive-linker",
"revive-stdlib",
"semver 1.0.23",
"serde",
"sha2",
"sha3",
"zkevm_opcode_defs",
]
[[package]] [[package]]
name = "revive-solidity" name = "revive-solidity"
version = "1.4.0" version = "1.4.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"colored", "colored",
"era-compiler-llvm-context",
"hex", "hex",
"inkwell", "inkwell",
"md5", "md5",
@@ -1711,7 +1800,8 @@ dependencies = [
"rayon", "rayon",
"regex", "regex",
"revive-common", "revive-common",
"semver 1.0.22", "revive-llvm-context",
"semver 1.0.23",
"serde", "serde",
"serde_json", "serde_json",
"sha3", "sha3",
@@ -1779,9 +1869,9 @@ checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343"
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.23" version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
@@ -1810,7 +1900,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [ dependencies = [
"semver 1.0.22", "semver 1.0.23",
] ]
[[package]] [[package]]
@@ -1840,9 +1930,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.17" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "same-file" name = "same-file"
@@ -1855,9 +1945,9 @@ dependencies = [
[[package]] [[package]]
name = "scale-info" name = "scale-info"
version = "2.11.2" version = "2.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024"
dependencies = [ dependencies = [
"bitvec", "bitvec",
"cfg-if", "cfg-if",
@@ -1868,11 +1958,11 @@ dependencies = [
[[package]] [[package]]
name = "scale-info-derive" name = "scale-info-derive"
version = "2.11.2" version = "2.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62"
dependencies = [ dependencies = [
"proc-macro-crate 1.3.1", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
@@ -1903,9 +1993,9 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.22" version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@@ -1921,29 +2011,29 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.198" version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.198" version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.116" version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -1994,9 +2084,9 @@ dependencies = [
[[package]] [[package]]
name = "sha3-asm" name = "sha3-asm"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac61da6b35ad76b195eb4771210f947734321a8d81d7738e1580d953bc7a15e" checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40"
dependencies = [ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
@@ -2059,6 +2149,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "structopt" name = "structopt"
version = "0.3.26" version = "0.3.26"
@@ -2102,9 +2198,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.60" version = "2.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2120,7 +2216,7 @@ dependencies = [
"paste", "paste",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
@@ -2152,22 +2248,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.59" version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.59" version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
@@ -2191,26 +2287,15 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.3" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.19.15" version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]]
name = "toml_edit"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"toml_datetime", "toml_datetime",
@@ -2261,9 +2346,15 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.11" version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "valuable" name = "valuable"
@@ -2323,7 +2414,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -2345,7 +2436,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -2397,9 +2488,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.7" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134306a13c5647ad6453e8deaec55d3a44d6021970129e6188735e74bf546697" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@@ -2569,22 +2660,22 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.32" version = "0.7.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.7.32" version = "0.7.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
@@ -2604,7 +2695,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.60", "syn 2.0.63",
] ]
[[package]] [[package]]
+5 -3
View File
@@ -27,9 +27,10 @@ path-slash = "0.2"
rayon = "1.8" rayon = "1.8"
structopt = { version = "0.3", default-features = false } structopt = { version = "0.3", default-features = false }
rand = "0.8" rand = "0.8"
polkavm-common = { branch = "master_byteswap", git = "https://github.com/koute/polkavm.git" } polkavm-common = { git = "https://github.com/koute/polkavm.git", rev = "266658b" }
polkavm-linker = { branch = "master_byteswap", git = "https://github.com/koute/polkavm.git" } polkavm-linker = { git = "https://github.com/koute/polkavm.git", rev = "266658b" }
polkavm = { branch = "master_byteswap", git = "https://github.com/koute/polkavm.git" } polkavm-disassembler = { git = "https://github.com/koute/polkavm.git", rev = "266658b" }
polkavm = { git = "https://github.com/koute/polkavm.git", rev = "266658b" }
alloy-primitives = "0.6" alloy-primitives = "0.6"
alloy-sol-types = "0.6" alloy-sol-types = "0.6"
env_logger = { version = "0.10.0", default-features = false } env_logger = { version = "0.10.0", default-features = false }
@@ -49,3 +50,4 @@ features = ["serde", "llvm18-0", "no-libffi-linking", "target-riscv"]
[profile.benchmark] [profile.benchmark]
inherits = "release" inherits = "release"
lto = true lto = true
codegen-units = 1
+11 -2
View File
@@ -1,4 +1,4 @@
.PHONY: install test test-solidity test-cli test-integration clean .PHONY: install format test test-solidity test-cli test-integration test-workspace clean
install: install-bin install-npm install: install-bin install-npm
@@ -8,7 +8,11 @@ install-bin:
install-npm: install-npm:
npm install && npm fund npm install && npm fund
test: install test-integration test-cli test-solidity format:
cargo fmt --all --check
test: format install test-cli test-workspace
cargo test --workspace
test-integration: install-bin test-integration: install-bin
cargo test --package revive-integration cargo test --package revive-integration
@@ -16,6 +20,9 @@ test-integration: install-bin
test-solidity: install test-solidity: install
cargo test --package revive-solidity cargo test --package revive-solidity
test-workspace: install
cargo test --workspace
test-cli: install test-cli: install
npm run test:cli npm run test:cli
@@ -38,6 +45,8 @@ bench: install-bin
cargo criterion --all --features bench-evm,bench-pvm --message-format=json \ cargo criterion --all --features bench-evm,bench-pvm --message-format=json \
| criterion-table > crates/benchmarks/BENCHMARKS.md | criterion-table > crates/benchmarks/BENCHMARKS.md
clippy:
cargo clippy --all-features --workspace --tests --benches
clean: clean:
cargo clean ; \ cargo clean ; \
+1 -1
View File
@@ -35,4 +35,4 @@ The project is in a very early PoC phase. Don't yet expect the produced code to
- [ ] Minimize scope of "stdlib" - [ ] Minimize scope of "stdlib"
- [ ] Document differences from EVM - [ ] Document differences from EVM
- [ ] Audit for bugs and correctness - [ ] Audit for bugs and correctness
- [ ] Rebranding - [x] Rebranding
+98
View File
@@ -0,0 +1,98 @@
# Benchmarks
## Table of Contents
- [Benchmark Results](#benchmark-results)
- [Baseline](#baseline)
- [OddPorduct](#oddporduct)
- [TriangleNumber](#trianglenumber)
- [FibonacciRecursive](#fibonaccirecursive)
- [FibonacciIterative](#fibonacciiterative)
- [PrepareBaseline](#preparebaseline)
- [PrepareOddProduct](#prepareoddproduct)
- [PrepareTriangleNumber](#preparetrianglenumber)
- [PrepareFibonacciRecursive](#preparefibonaccirecursive)
- [PrepareFibonacciIterative](#preparefibonacciiterative)
## Benchmark Results
### Baseline
| | `EVM` | `PVMInterpreter` | `PVM` |
|:--------|:--------------------------|:---------------------------------|:--------------------------------- |
| **`0`** | `900.78 ns` (✅ **1.00x**) | `715.00 ns` (✅ **1.26x faster**) | `26.22 us` (❌ *29.11x slower*) |
### OddPorduct
| | `EVM` | `PVMInterpreter` | `PVM` |
|:----------------|:--------------------------|:---------------------------------|:--------------------------------- |
| **`300000`** | `223.94 ms` (✅ **1.00x**) | `125.43 ms` (✅ **1.79x faster**) | `2.56 ms` (🚀 **87.60x faster**) |
| **`1200000`** | `907.18 ms` (✅ **1.00x**) | `486.46 ms` (🚀 **1.86x faster**) | `9.96 ms` (🚀 **91.10x faster**) |
| **`12000000`** | `9.41 s` (✅ **1.00x**) | `4.96 s` (🚀 **1.90x faster**) | `98.26 ms` (🚀 **95.75x faster**) |
| **`180000000`** | `133.65 s` (✅ **1.00x**) | `73.98 s` (🚀 **1.81x faster**) | `1.48 s` (🚀 **90.04x faster**) |
| **`720000000`** | `543.61 s` (✅ **1.00x**) | `295.27 s` (🚀 **1.84x faster**) | `6.14 s` (🚀 **88.55x faster**) |
### TriangleNumber
| | `EVM` | `PVMInterpreter` | `PVM` |
|:----------------|:--------------------------|:---------------------------------|:--------------------------------- |
| **`360000`** | `174.29 ms` (✅ **1.00x**) | `134.93 ms` (✅ **1.29x faster**) | `2.58 ms` (🚀 **67.43x faster**) |
| **`1440000`** | `723.79 ms` (✅ **1.00x**) | `518.44 ms` (✅ **1.40x faster**) | `9.93 ms` (🚀 **72.92x faster**) |
| **`14400000`** | `7.03 s` (✅ **1.00x**) | `5.40 s` (✅ **1.30x faster**) | `99.93 ms` (🚀 **70.40x faster**) |
| **`216000000`** | `108.98 s` (✅ **1.00x**) | `77.85 s` (✅ **1.40x faster**) | `1.44 s` (🚀 **75.78x faster**) |
| **`864000000`** | `423.03 s` (✅ **1.00x**) | `323.22 s` (✅ **1.31x faster**) | `5.99 s` (🚀 **70.61x faster**) |
### FibonacciRecursive
| | `EVM` | `PVMInterpreter` | `PVM` |
|:---------|:--------------------------|:---------------------------------|:---------------------------------- |
| **`24`** | `80.63 ms` (✅ **1.00x**) | `159.96 ms` (❌ *1.98x slower*) | `2.73 ms` (🚀 **29.52x faster**) |
| **`27`** | `331.93 ms` (✅ **1.00x**) | `662.76 ms` (❌ *2.00x slower*) | `10.78 ms` (🚀 **30.79x faster**) |
| **`31`** | `2.35 s` (✅ **1.00x**) | `4.44 s` (❌ *1.88x slower*) | `76.69 ms` (🚀 **30.69x faster**) |
| **`36`** | `26.17 s` (✅ **1.00x**) | `51.08 s` (❌ *1.95x slower*) | `819.30 ms` (🚀 **31.94x faster**) |
| **`39`** | `110.50 s` (✅ **1.00x**) | `220.00 s` (❌ *1.99x slower*) | `3.46 s` (🚀 **31.90x faster**) |
### FibonacciIterative
| | `EVM` | `PVMInterpreter` | `PVM` |
|:----------------|:--------------------------|:---------------------------------|:---------------------------------- |
| **`256`** | `84.27 us` (✅ **1.00x**) | `291.83 us` (❌ *3.46x slower*) | `42.87 us` (🚀 **1.97x faster**) |
| **`162500`** | `53.32 ms` (✅ **1.00x**) | `174.85 ms` (❌ *3.28x slower*) | `2.57 ms` (🚀 **20.78x faster**) |
| **`650000`** | `217.77 ms` (✅ **1.00x**) | `699.77 ms` (❌ *3.21x slower*) | `9.91 ms` (🚀 **21.96x faster**) |
| **`6500000`** | `2.14 s` (✅ **1.00x**) | `6.89 s` (❌ *3.22x slower*) | `100.67 ms` (🚀 **21.22x faster**) |
| **`100000000`** | `31.96 s` (✅ **1.00x**) | `106.46 s` (❌ *3.33x slower*) | `1.50 s` (🚀 **21.28x faster**) |
| **`400000000`** | `128.68 s` (✅ **1.00x**) | `447.34 s` (❌ *3.48x slower*) | `6.19 s` (🚀 **20.77x faster**) |
### PrepareBaseline
| | `Evm` | `PVMInterpreterCompile` | `PVMInterpreterInstantiate` | `PVMCompile` | `PVMInstantiate` |
|:--------|:--------------------------|:---------------------------------|:-------------------------------------|:----------------------------------|:---------------------------------- |
| **`0`** | `179.68 ns` (✅ **1.00x**) | `506.01 ns` (❌ *2.82x slower*) | `1.70 us` (❌ *9.45x slower*) | `29.44 us` (❌ *163.87x slower*) | `69.01 us` (❌ *384.08x slower*) |
### PrepareOddProduct
| | `Evm` | `PVMInterpreterCompile` | `PVMInterpreterInstantiate` | `PVMCompile` | `PVMInstantiate` |
|:--------|:--------------------------|:---------------------------------|:-------------------------------------|:---------------------------------|:---------------------------------- |
| **`0`** | `509.96 ns` (✅ **1.00x**) | `485.20 ns` (✅ **1.05x faster**) | `1.69 us` (❌ *3.32x slower*) | `29.88 us` (❌ *58.59x slower*) | `70.20 us` (❌ *137.66x slower*) |
### PrepareTriangleNumber
| | `Evm` | `PVMInterpreterCompile` | `PVMInterpreterInstantiate` | `PVMCompile` | `PVMInstantiate` |
|:--------|:--------------------------|:---------------------------------|:-------------------------------------|:---------------------------------|:---------------------------------- |
| **`0`** | `508.44 ns` (✅ **1.00x**) | `528.74 ns` (✅ **1.04x slower**) | `1.83 us` (❌ *3.60x slower*) | `50.81 us` (❌ *99.94x slower*) | `68.37 us` (❌ *134.48x slower*) |
### PrepareFibonacciRecursive
| | `Evm` | `PVMInterpreterCompile` | `PVMInterpreterInstantiate` | `PVMCompile` | `PVMInstantiate` |
|:--------|:--------------------------|:---------------------------------|:-------------------------------------|:----------------------------------|:---------------------------------- |
| **`0`** | `409.24 ns` (✅ **1.00x**) | `507.67 ns` (❌ *1.24x slower*) | `1.80 us` (❌ *4.40x slower*) | `46.24 us` (❌ *112.99x slower*) | `69.06 us` (❌ *168.76x slower*) |
### PrepareFibonacciIterative
| | `Evm` | `PVMInterpreterCompile` | `PVMInterpreterInstantiate` | `PVMCompile` | `PVMInstantiate` |
|:--------|:--------------------------|:---------------------------------|:-------------------------------------|:----------------------------------|:---------------------------------- |
| **`0`** | `304.00 ns` (✅ **1.00x**) | `524.75 ns` (❌ *1.73x slower*) | `1.88 us` (❌ *6.17x slower*) | `43.50 us` (❌ *143.11x slower*) | `66.82 us` (❌ *219.80x slower*) |
---
Made with [criterion-table](https://github.com/nu11ptr/criterion-table)
+34 -64
View File
@@ -5,10 +5,6 @@ use criterion::{
criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, BenchmarkId, criterion_group, criterion_main, measurement::Measurement, BenchmarkGroup, BenchmarkId,
Criterion, Criterion,
}; };
#[cfg(any(feature = "bench-pvm-interpreter", feature = "bench-pvm"))]
use polkavm::BackendKind;
use revive_benchmarks::prepare_pvm;
use revive_integration::cases::Contract; use revive_integration::cases::Contract;
fn bench<P, L, I, M>(mut group: BenchmarkGroup<'_, M>, parameters: &[P], labels: &[L], contract: I) fn bench<P, L, I, M>(mut group: BenchmarkGroup<'_, M>, parameters: &[P], labels: &[L], contract: I)
@@ -35,14 +31,14 @@ where
#[cfg(feature = "bench-pvm-interpreter")] #[cfg(feature = "bench-pvm-interpreter")]
{ {
let contract = contract(p.clone()); let contract = contract(p.clone());
let (state, mut instance, export) = prepare_pvm( let (transaction, mut instance, export) = revive_benchmarks::prepare_pvm(
&contract.pvm_runtime, &contract.pvm_runtime,
&contract.calldata, contract.calldata,
BackendKind::Interpreter, polkavm::BackendKind::Interpreter,
); );
group.bench_with_input(BenchmarkId::new("PVMInterpreter", l), p, |b, _| { group.bench_with_input(BenchmarkId::new("PVMInterpreter", l), p, |b, _| {
b.iter(|| { b.iter(|| {
revive_integration::mock_runtime::call(state.clone(), &mut instance, export); transaction.clone().call_on(&mut instance, export);
}); });
}); });
} }
@@ -50,14 +46,14 @@ where
#[cfg(feature = "bench-pvm")] #[cfg(feature = "bench-pvm")]
{ {
let contract = contract(p.clone()); let contract = contract(p.clone());
let (state, mut instance, export) = prepare_pvm( let (transaction, mut instance, export) = revive_benchmarks::prepare_pvm(
&contract.pvm_runtime, &contract.pvm_runtime,
&contract.calldata, contract.calldata,
BackendKind::Compiler, polkavm::BackendKind::Compiler,
); );
group.bench_with_input(BenchmarkId::new("PVM", l), p, |b, _| { group.bench_with_input(BenchmarkId::new("PVM", l), p, |b, _| {
b.iter(|| { b.iter(|| {
revive_integration::mock_runtime::call(state.clone(), &mut instance, export); transaction.clone().call_on(&mut instance, export);
}); });
}); });
} }
@@ -66,40 +62,34 @@ where
group.finish(); group.finish();
} }
#[cfg(feature = "bench-extensive")] fn group<'error, M>(c: &'error mut Criterion<M>, group_name: &str) -> BenchmarkGroup<'error, M>
fn group_extensive<'error, M>(
c: &'error mut Criterion<M>,
group_name: &str,
) -> BenchmarkGroup<'error, M>
where where
M: Measurement, M: Measurement,
{ {
let mut group = c.benchmark_group(group_name); #[cfg(feature = "bench-extensive")]
group {
.sample_size(10) let mut group = c.benchmark_group(group_name);
.measurement_time(Duration::from_secs(60)); group
group .sample_size(10)
.measurement_time(Duration::from_secs(60));
group
}
#[cfg(not(feature = "bench-extensive"))]
return c.benchmark_group(group_name);
} }
fn bench_baseline(c: &mut Criterion) { fn bench_baseline(c: &mut Criterion) {
let group = group(c, "Baseline");
let parameters = &[0u8]; let parameters = &[0u8];
bench( bench(group, parameters, parameters, |_| Contract::baseline());
c.benchmark_group("Baseline"),
parameters,
parameters,
|_| Contract::baseline(),
);
} }
fn bench_odd_product(c: &mut Criterion) { fn bench_odd_product(c: &mut Criterion) {
let group = group(c, "OddPorduct");
#[cfg(feature = "bench-extensive")] #[cfg(feature = "bench-extensive")]
let group = group_extensive(c, "OddProduct"); let parameters = &[300000, 1200000, 12000000, 180000000, 720000000];
#[cfg(not(feature = "bench-extensive"))]
let group = c.benchmark_group("OddProduct");
#[cfg(feature = "bench-extensive")]
let parameters = &[2_000_000i32, 4_000_000, 8_000_000, 120_000_000];
#[cfg(not(feature = "bench-extensive"))] #[cfg(not(feature = "bench-extensive"))]
let parameters = &[10_000, 100_000]; let parameters = &[10_000, 100_000];
@@ -107,13 +97,9 @@ fn bench_odd_product(c: &mut Criterion) {
} }
fn bench_triangle_number(c: &mut Criterion) { fn bench_triangle_number(c: &mut Criterion) {
let group = group(c, "TriangleNumber");
#[cfg(feature = "bench-extensive")] #[cfg(feature = "bench-extensive")]
let group = group_extensive(c, "TriangleNumber"); let parameters = &[360000, 1440000, 14400000, 216000000, 864000000];
#[cfg(not(feature = "bench-extensive"))]
let group = c.benchmark_group("TriangleNumber");
#[cfg(feature = "bench-extensive")]
let parameters = &[3_000_000i64, 6_000_000, 12_000_000, 180_000_000];
#[cfg(not(feature = "bench-extensive"))] #[cfg(not(feature = "bench-extensive"))]
let parameters = &[10_000, 100_000]; let parameters = &[10_000, 100_000];
@@ -121,13 +107,9 @@ fn bench_triangle_number(c: &mut Criterion) {
} }
fn bench_fibonacci_recurisve(c: &mut Criterion) { fn bench_fibonacci_recurisve(c: &mut Criterion) {
#[cfg(not(feature = "bench-extensive"))] let group = group(c, "FibonacciRecursive");
let group = c.benchmark_group("FibonacciRecursive");
#[cfg(feature = "bench-extensive")] #[cfg(feature = "bench-extensive")]
let group = group_extensive(c, "FibonacciRecursive"); let parameters = &[24, 27, 31, 36, 39];
#[cfg(feature = "bench-extensive")]
let parameters = &[26, 30, 34, 38];
#[cfg(not(feature = "bench-extensive"))] #[cfg(not(feature = "bench-extensive"))]
let parameters = &[12, 16, 20]; let parameters = &[12, 16, 20];
@@ -135,13 +117,9 @@ fn bench_fibonacci_recurisve(c: &mut Criterion) {
} }
fn bench_fibonacci_iterative(c: &mut Criterion) { fn bench_fibonacci_iterative(c: &mut Criterion) {
#[cfg(not(feature = "bench-extensive"))] let group = group(c, "FibonacciIterative");
let group = c.benchmark_group("FibonacciIterative");
#[cfg(feature = "bench-extensive")] #[cfg(feature = "bench-extensive")]
let group = group_extensive(c, "FibonacciIterative"); let parameters = &[256, 162500, 650000, 6500000, 100000000, 400000000];
#[cfg(feature = "bench-extensive")]
let parameters = &[256, 100000, 1000000, 100000000];
#[cfg(not(feature = "bench-extensive"))] #[cfg(not(feature = "bench-extensive"))]
let parameters = &[64, 128, 256]; let parameters = &[64, 128, 256];
@@ -149,26 +127,18 @@ fn bench_fibonacci_iterative(c: &mut Criterion) {
} }
fn bench_fibonacci_binet(c: &mut Criterion) { fn bench_fibonacci_binet(c: &mut Criterion) {
let group = group(c, "FibonacciBinet");
let parameters = &[64, 128, 256]; let parameters = &[64, 128, 256];
bench( bench(group, parameters, parameters, Contract::fib_binet);
c.benchmark_group("FibonacciBinet"),
parameters,
parameters,
Contract::fib_binet,
);
} }
fn bench_sha1(c: &mut Criterion) { fn bench_sha1(c: &mut Criterion) {
let group = group(c, "SHA1");
let parameters = &[vec![0xff], vec![0xff; 64], vec![0xff; 512]]; let parameters = &[vec![0xff], vec![0xff; 64], vec![0xff; 512]];
let labels = parameters.iter().map(|p| p.len()).collect::<Vec<_>>(); let labels = parameters.iter().map(|p| p.len()).collect::<Vec<_>>();
bench( bench(group, parameters, &labels, Contract::sha1);
c.benchmark_group("SHA1"),
parameters,
&labels,
Contract::sha1,
);
} }
criterion_group!( criterion_group!(
+4 -6
View File
@@ -1,7 +1,5 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use polkavm::BackendKind;
use revive_benchmarks::instantiate_engine;
use revive_integration::cases::Contract; use revive_integration::cases::Contract;
fn bench( fn bench(
@@ -22,7 +20,7 @@ fn bench(
#[cfg(feature = "bench-pvm-interpreter")] #[cfg(feature = "bench-pvm-interpreter")]
{ {
let engine = instantiate_engine(BackendKind::Interpreter); let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Interpreter);
group.bench_with_input( group.bench_with_input(
BenchmarkId::new("PVMInterpreterCompile", code_size), BenchmarkId::new("PVMInterpreterCompile", code_size),
&(&pvm_runtime, engine), &(&pvm_runtime, engine),
@@ -36,7 +34,7 @@ fn bench(
#[cfg(feature = "bench-pvm-interpreter")] #[cfg(feature = "bench-pvm-interpreter")]
{ {
let engine = instantiate_engine(BackendKind::Interpreter); let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Interpreter);
let module = revive_integration::mock_runtime::recompile_code(&pvm_runtime, &engine); let module = revive_integration::mock_runtime::recompile_code(&pvm_runtime, &engine);
group.bench_with_input( group.bench_with_input(
BenchmarkId::new("PVMInterpreterInstantiate", code_size), BenchmarkId::new("PVMInterpreterInstantiate", code_size),
@@ -51,7 +49,7 @@ fn bench(
#[cfg(feature = "bench-pvm")] #[cfg(feature = "bench-pvm")]
{ {
let engine = instantiate_engine(BackendKind::Compiler); let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Compiler);
group.bench_with_input( group.bench_with_input(
BenchmarkId::new("PVMCompile", code_size), BenchmarkId::new("PVMCompile", code_size),
&(&pvm_runtime, engine), &(&pvm_runtime, engine),
@@ -65,7 +63,7 @@ fn bench(
#[cfg(feature = "bench-pvm")] #[cfg(feature = "bench-pvm")]
{ {
let engine = instantiate_engine(BackendKind::Compiler); let engine = revive_benchmarks::instantiate_engine(polkavm::BackendKind::Compiler);
let module = revive_integration::mock_runtime::recompile_code(&pvm_runtime, &engine); let module = revive_integration::mock_runtime::recompile_code(&pvm_runtime, &engine);
group.bench_with_input( group.bench_with_input(
BenchmarkId::new("PVMInstantiate", code_size), BenchmarkId::new("PVMInstantiate", code_size),
+6 -5
View File
@@ -1,19 +1,20 @@
use polkavm::{BackendKind, Config, Engine, ExportIndex, Instance, SandboxKind}; use polkavm::{BackendKind, Config, Engine, ExportIndex, Instance, SandboxKind};
use revive_integration::mock_runtime; use revive_integration::mock_runtime::{self, TransactionBuilder};
use revive_integration::mock_runtime::State; use revive_integration::mock_runtime::{State, Transaction};
pub fn prepare_pvm( pub fn prepare_pvm(
code: &[u8], code: &[u8],
input: &[u8], input: Vec<u8>,
backend: BackendKind, backend: BackendKind,
) -> (State, Instance<State>, ExportIndex) { ) -> (TransactionBuilder, Instance<Transaction>, ExportIndex) {
let mut config = Config::new(); let mut config = Config::new();
config.set_backend(Some(backend)); config.set_backend(Some(backend));
config.set_sandbox(Some(SandboxKind::Linux)); config.set_sandbox(Some(SandboxKind::Linux));
let (instance, export_index) = mock_runtime::prepare(code, Some(config)); let (instance, export_index) = mock_runtime::prepare(code, Some(config));
let transaction = State::default().transaction().calldata(input);
(State::new(input.to_vec()), instance, export_index) (transaction, instance, export_index)
} }
pub fn instantiate_engine(backend: BackendKind) -> Engine { pub fn instantiate_engine(backend: BackendKind) -> Engine {
+1 -26
View File
@@ -1,13 +1,4 @@
# zkSync Era: Compiler Common # revive: Compiler Common
[![Logo](eraLogo.svg)](https://zksync.io/)
zkSync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security
or decentralization. As it's EVM-compatible (with Solidity/Vyper), 99% of Ethereum projects can redeploy without
needing to refactor or re-audit any code. zkSync Era also uses an LLVM-based compiler that will eventually enable
developers to write smart contracts in popular languages such as C++ and Rust.
This repository contains the common compiler constants.
## License ## License
@@ -17,19 +8,3 @@ This library is distributed under the terms of either
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>) - MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option. at your option.
## Official Links
- [Website](https://zksync.io/)
- [GitHub](https://github.com/matter-labs)
- [Twitter](https://twitter.com/zksync)
- [Twitter for Devs](https://twitter.com/zkSyncDevs)
- [Discord](https://join.zksync.dev/)
## Disclaimer
zkSync Era has been through extensive testing and audits, and although it is live, it is still in alpha state and
will undergo further audits and bug bounty programs. We would love to hear our community's thoughts and suggestions
about it!
It's important to note that forking it now could potentially lead to missing important
security updates, critical features, and performance improvements.
-2
View File
@@ -1,6 +1,4 @@
//!
//! The number base constants. //! The number base constants.
//!
/// The binary number base. /// The binary number base.
pub const BASE_BINARY: u32 = 2; pub const BASE_BINARY: u32 = 2;
+10 -4
View File
@@ -1,6 +1,4 @@
//!
//! The common sizes in bits. //! The common sizes in bits.
//!
/// The `bool` type bit-length. /// The `bool` type bit-length.
pub const BIT_LENGTH_BOOLEAN: usize = 1; pub const BIT_LENGTH_BOOLEAN: usize = 1;
@@ -18,8 +16,16 @@ pub const BIT_LENGTH_X64: usize = crate::byte_length::BYTE_LENGTH_X64 * BIT_LENG
pub const BIT_LENGTH_ETH_ADDRESS: usize = pub const BIT_LENGTH_ETH_ADDRESS: usize =
crate::byte_length::BYTE_LENGTH_ETH_ADDRESS * BIT_LENGTH_BYTE; crate::byte_length::BYTE_LENGTH_ETH_ADDRESS * BIT_LENGTH_BYTE;
/// The field (usually `u256` or `i256`) bit-length. /// The VM word (usually `u256` or `i256`) bit-length.
pub const BIT_LENGTH_FIELD: usize = crate::byte_length::BYTE_LENGTH_FIELD * BIT_LENGTH_BYTE; pub const BIT_LENGTH_WORD: usize = crate::byte_length::BYTE_LENGTH_WORD * BIT_LENGTH_BYTE;
/// Bit length of the runtime value type. /// Bit length of the runtime value type.
pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE; pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE;
/// Bit length of thre runimte block number type.
pub const BIT_LENGTH_BLOCK_NUMBER: usize =
crate::byte_length::BYTE_LENGTH_BLOCK_NUMBER * BIT_LENGTH_BYTE;
/// Bit length of thre runimte block timestamp type.
pub const BIT_LENGTH_BLOCK_TIMESTAMP: usize =
crate::byte_length::BYTE_LENGTH_BLOCK_TIMESTAMP * BIT_LENGTH_BYTE;
+9 -5
View File
@@ -1,6 +1,4 @@
//!
//! The common sizes in bytes. //! The common sizes in bytes.
//!
/// The byte-length. /// The byte-length.
pub const BYTE_LENGTH_BYTE: usize = 1; pub const BYTE_LENGTH_BYTE: usize = 1;
@@ -17,8 +15,14 @@ pub const BYTE_LENGTH_X64: usize = 8;
/// The ETH address byte-length. /// The ETH address byte-length.
pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20; pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20;
/// The field byte-length. /// The word byte-length.
pub const BYTE_LENGTH_FIELD: usize = 32; pub const BYTE_LENGTH_WORD: usize = 32;
/// Byte length of the runtime value type. /// Byte length of the runtime value type.
pub const BYTE_LENGTH_VALUE: usize = 16; pub const BYTE_LENGTH_VALUE: usize = 32;
/// Byte length of the runtime block number type.
pub const BYTE_LENGTH_BLOCK_NUMBER: usize = 8;
/// Byte length of the runtime block timestamp type.
pub const BYTE_LENGTH_BLOCK_TIMESTAMP: usize = 8;
-117
View File
@@ -1,117 +0,0 @@
//!
//! The EraVM address constants.
//!
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_TO_L1: u16 = 0xFFFF;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_PRECOMPILE: u16 = 0xFFFD;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_META: u16 = 0xFFFC;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_MIMIC_CALL: u16 = 0xFFFB;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_SYSTEM_MIMIC_CALL: u16 = 0xFFFA;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_MIMIC_CALL_BYREF: u16 = 0xFFF9;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_SYSTEM_MIMIC_CALL_BYREF: u16 = 0xFFF8;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_RAW_FAR_CALL: u16 = 0xFFF7;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_RAW_FAR_CALL_BYREF: u16 = 0xFFF6;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_SYSTEM_CALL: u16 = 0xFFF5;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_SYSTEM_CALL_BYREF: u16 = 0xFFF4;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_SET_CONTEXT_VALUE_CALL: u16 = 0xFFF3;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_SET_PUBDATA_PRICE: u16 = 0xFFF2;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_INCREMENT_TX_COUNTER: u16 = 0xFFF1;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_GET_GLOBAL_PTR_CALLDATA: u16 = 0xFFF0;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_GET_GLOBAL_CALL_FLAGS: u16 = 0xFFEF;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_GET_GLOBAL_PTR_RETURN_DATA: u16 = 0xFFEE;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_EVENT_INITIALIZE: u16 = 0xFFED;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_EVENT_WRITE: u16 = 0xFFEC;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_LOAD_CALLDATA: u16 = 0xFFEB;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_LOAD_RETURN_DATA: u16 = 0xFFEA;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_ADD: u16 = 0xFFE9;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_SHRINK: u16 = 0xFFE8;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_PACK: u16 = 0xFFE7;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_MULTIPLICATION_HIGH_REGISTER: u16 = 0xFFE6;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_GET_GLOBAL_EXTRA_ABI_DATA: u16 = 0xFFE5;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_DATA_LOAD: u16 = 0xFFE4;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_DATA_COPY: u16 = 0xFFE3;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_DATA_SIZE: u16 = 0xFFE2;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_CONST_ARRAY_DECLARE: u16 = 0xFFE1;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_CONST_ARRAY_SET: u16 = 0xFFE0;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_CONST_ARRAY_FINALIZE: u16 = 0xFFDF;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_CONST_ARRAY_GET: u16 = 0xFFDE;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_DECOMMIT: u16 = 0xFFDD;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_LOAD_DECOMMIT: u16 = 0xFFDC;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_RETURN_FORWARD: u16 = 0xFFDB;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_REVERT_FORWARD: u16 = 0xFFDA;
/// The corresponding simulation predefined address.
pub const ERAVM_ADDRESS_ACTIVE_PTR_SWAP: u16 = 0xFFD9;
-5
View File
@@ -1,5 +0,0 @@
//!
//! The EraVM constants.
//!
pub mod address;
-4
View File
@@ -1,13 +1,9 @@
//!
//! The EVM version. //! The EVM version.
//!
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
///
/// The EVM version. /// The EVM version.
///
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub enum EVMVersion { pub enum EVMVersion {
+4 -6
View File
@@ -1,6 +1,4 @@
//!
//! The file extensions. //! The file extensions.
//!
/// The manifest file extension. /// The manifest file extension.
pub static EXTENSION_MANIFEST: &str = "toml"; pub static EXTENSION_MANIFEST: &str = "toml";
@@ -41,8 +39,8 @@ pub static EXTENSION_LLVM_SOURCE: &str = "ll";
/// The LLVM bitcode file extension. /// The LLVM bitcode file extension.
pub static EXTENSION_LLVM_BINARY: &str = "bc"; pub static EXTENSION_LLVM_BINARY: &str = "bc";
/// The EraVM assembly file extension. /// The PolkaVM assembly file extension.
pub static EXTENSION_ERAVM_ASSEMBLY: &str = "zasm"; pub static EXTENSION_POLKAVM_ASSEMBLY: &str = "pvmasm";
/// The EraVM bytecode file extension. /// The PolkaVM bytecode file extension.
pub static EXTENSION_ERAVM_BINARY: &str = "zbin"; pub static EXTENSION_POLKAVM_BINARY: &str = "pvm";
+2 -4
View File
@@ -1,21 +1,19 @@
//!
//! The compiler common library. //! The compiler common library.
//!
pub(crate) mod base; pub(crate) mod base;
pub(crate) mod bit_length; pub(crate) mod bit_length;
pub(crate) mod byte_length; pub(crate) mod byte_length;
pub(crate) mod eravm;
pub(crate) mod evm_version; pub(crate) mod evm_version;
pub(crate) mod exit_code; pub(crate) mod exit_code;
pub(crate) mod extension; pub(crate) mod extension;
pub(crate) mod polkavm;
pub(crate) mod utils; pub(crate) mod utils;
pub use self::base::*; pub use self::base::*;
pub use self::bit_length::*; pub use self::bit_length::*;
pub use self::byte_length::*; pub use self::byte_length::*;
pub use self::eravm::address::*;
pub use self::evm_version::EVMVersion; pub use self::evm_version::EVMVersion;
pub use self::exit_code::*; pub use self::exit_code::*;
pub use self::extension::*; pub use self::extension::*;
pub use self::polkavm::address::*;
pub use self::utils::*; pub use self::utils::*;
+115
View File
@@ -0,0 +1,115 @@
//! The PolkaVM address constants.
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_TO_L1: u16 = 0xFFFF;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_PRECOMPILE: u16 = 0xFFFD;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_META: u16 = 0xFFFC;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_MIMIC_CALL: u16 = 0xFFFB;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_MIMIC_CALL: u16 = 0xFFFA;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_MIMIC_CALL_BYREF: u16 = 0xFFF9;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_MIMIC_CALL_BYREF: u16 = 0xFFF8;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_RAW_FAR_CALL: u16 = 0xFFF7;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_RAW_FAR_CALL_BYREF: u16 = 0xFFF6;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_CALL: u16 = 0xFFF5;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SYSTEM_CALL_BYREF: u16 = 0xFFF4;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SET_CONTEXT_VALUE_CALL: u16 = 0xFFF3;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_SET_PUBDATA_PRICE: u16 = 0xFFF2;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_INCREMENT_TX_COUNTER: u16 = 0xFFF1;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_PTR_CALLDATA: u16 = 0xFFF0;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_CALL_FLAGS: u16 = 0xFFEF;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_PTR_RETURN_DATA: u16 = 0xFFEE;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_EVENT_INITIALIZE: u16 = 0xFFED;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_EVENT_WRITE: u16 = 0xFFEC;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_CALLDATA: u16 = 0xFFEB;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_RETURN_DATA: u16 = 0xFFEA;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_ADD: u16 = 0xFFE9;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_SHRINK: u16 = 0xFFE8;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_PACK: u16 = 0xFFE7;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_MULTIPLICATION_HIGH_REGISTER: u16 = 0xFFE6;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_GET_GLOBAL_EXTRA_ABI_DATA: u16 = 0xFFE5;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_LOAD: u16 = 0xFFE4;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_COPY: u16 = 0xFFE3;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_DATA_SIZE: u16 = 0xFFE2;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_DECLARE: u16 = 0xFFE1;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_SET: u16 = 0xFFE0;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_FINALIZE: u16 = 0xFFDF;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_CONST_ARRAY_GET: u16 = 0xFFDE;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_DECOMMIT: u16 = 0xFFDD;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_LOAD_DECOMMIT: u16 = 0xFFDC;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_RETURN_FORWARD: u16 = 0xFFDB;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_REVERT_FORWARD: u16 = 0xFFDA;
/// The corresponding simulation predefined address.
pub const POLKAVM_ADDRESS_ACTIVE_PTR_SWAP: u16 = 0xFFD9;
+5
View File
@@ -0,0 +1,5 @@
//!
//! The PolkaVM constants.
//!
pub mod address;
-8
View File
@@ -1,12 +1,7 @@
//!
//! The compiler common utils. //! The compiler common utils.
//!
///
/// Deserializes a `serde_json` object from slice with the recursion limit disabled. /// Deserializes a `serde_json` object from slice with the recursion limit disabled.
///
/// Must be used for all JSON I/O to avoid crashes due to the aforementioned limit. /// Must be used for all JSON I/O to avoid crashes due to the aforementioned limit.
///
pub fn deserialize_from_slice<O>(input: &[u8]) -> anyhow::Result<O> pub fn deserialize_from_slice<O>(input: &[u8]) -> anyhow::Result<O>
where where
O: serde::de::DeserializeOwned, O: serde::de::DeserializeOwned,
@@ -18,11 +13,8 @@ where
Ok(result) Ok(result)
} }
///
/// Deserializes a `serde_json` object from string with the recursion limit disabled. /// Deserializes a `serde_json` object from string with the recursion limit disabled.
///
/// Must be used for all JSON I/O to avoid crashes due to the aforementioned limit. /// Must be used for all JSON I/O to avoid crashes due to the aforementioned limit.
///
pub fn deserialize_from_str<O>(input: &str) -> anyhow::Result<O> pub fn deserialize_from_str<O>(input: &str) -> anyhow::Result<O>
where where
O: serde::de::DeserializeOwned, O: serde::de::DeserializeOwned,
+1
View File
@@ -8,3 +8,4 @@ edition = "2021"
[dependencies] [dependencies]
evm-interpreter = { workspace = true } evm-interpreter = { workspace = true }
primitive-types = { workspace = true } primitive-types = { workspace = true }
alloy-primitives = { workspace = true }
+19 -14
View File
@@ -1,3 +1,4 @@
use alloy_primitives::{keccak256, Address, B256};
use evm_interpreter::{ use evm_interpreter::{
interpreter::{EtableInterpreter, RunInterpreter}, interpreter::{EtableInterpreter, RunInterpreter},
trap::CallCreateTrap, trap::CallCreateTrap,
@@ -9,20 +10,23 @@ use primitive_types::{H160, H256, U256};
static RUNTIME_ETABLE: Etable<RuntimeState, UnimplementedHandler, CallCreateTrap> = static RUNTIME_ETABLE: Etable<RuntimeState, UnimplementedHandler, CallCreateTrap> =
Etable::runtime(); Etable::runtime();
pub struct UnimplementedHandler; #[derive(Default)]
pub struct UnimplementedHandler {
logs: Vec<Log>,
}
impl RuntimeEnvironment for UnimplementedHandler { impl RuntimeEnvironment for UnimplementedHandler {
fn block_hash(&self, _number: U256) -> H256 { fn block_hash(&self, _number: U256) -> H256 {
unimplemented!() unimplemented!()
} }
fn block_number(&self) -> U256 { fn block_number(&self) -> U256 {
unimplemented!() U256::from(123)
} }
fn block_coinbase(&self) -> H160 { fn block_coinbase(&self) -> H160 {
unimplemented!() unimplemented!()
} }
fn block_timestamp(&self) -> U256 { fn block_timestamp(&self) -> U256 {
unimplemented!() U256::from(456)
} }
fn block_difficulty(&self) -> U256 { fn block_difficulty(&self) -> U256 {
unimplemented!() unimplemented!()
@@ -86,8 +90,9 @@ impl RuntimeBackend for UnimplementedHandler {
fn set_storage(&mut self, _address: H160, _index: H256, _value: H256) -> Result<(), ExitError> { fn set_storage(&mut self, _address: H160, _index: H256, _value: H256) -> Result<(), ExitError> {
unimplemented!() unimplemented!()
} }
fn log(&mut self, _log: Log) -> Result<(), ExitError> { fn log(&mut self, log: Log) -> Result<(), ExitError> {
unimplemented!() self.logs.push(log);
Ok(())
} }
fn mark_delete(&mut self, _address: H160) { fn mark_delete(&mut self, _address: H160) {
unimplemented!() unimplemented!()
@@ -123,10 +128,13 @@ pub struct PreparedEvm {
} }
pub fn prepare(code: Vec<u8>, data: Vec<u8>) -> PreparedEvm { pub fn prepare(code: Vec<u8>, data: Vec<u8>) -> PreparedEvm {
let address = Address::default().create2(B256::default(), keccak256([]).0);
let caller = Address::default().create2(B256::default(), keccak256([]).0);
let state = RuntimeState { let state = RuntimeState {
context: Context { context: Context {
address: H160::default(), address: H160::from(address.0 .0),
caller: H160::default(), caller: H160::from(caller.0 .0),
apparent_value: U256::default(), apparent_value: U256::default(),
}, },
transaction_context: TransactionContext { transaction_context: TransactionContext {
@@ -143,12 +151,9 @@ pub fn prepare(code: Vec<u8>, data: Vec<u8>) -> PreparedEvm {
} }
} }
pub fn execute(pre: PreparedEvm) -> Vec<u8> { pub fn execute(pre: PreparedEvm) -> (Vec<u8>, Vec<Log>) {
let mut vm = EtableInterpreter::new_valid(pre.vm, &RUNTIME_ETABLE, pre.valids); let mut vm = EtableInterpreter::new_valid(pre.vm, &RUNTIME_ETABLE, pre.valids);
vm.run(&mut UnimplementedHandler {}) let mut handler = UnimplementedHandler::default();
.exit() vm.run(&mut handler).exit().unwrap().unwrap();
.unwrap() (vm.retval.clone(), handler.logs)
.unwrap();
vm.retval.clone()
} }
+1 -1
View File
@@ -5,7 +5,7 @@ fn compile(source_path: &str, output_path: &str) {
.args([ .args([
"-O3", "-O3",
"-filetype=asm", "-filetype=asm",
"-mattr=+zbb,+e,+m", "-mattr=+zbb,+e",
source_path, source_path,
"-o", "-o",
output_path, output_path,
-1
View File
@@ -9,7 +9,6 @@ include!(concat!(env!("OUT_DIR"), "/bswap.rs"));
/// - Takes a `i256` value argument /// - Takes a `i256` value argument
/// - Byte swaps it using `rev8` from the `zbb` extension /// - Byte swaps it using `rev8` from the `zbb` extension
/// - Returns the `i256` value /// - Returns the `i256` value
///
/// Returns `Error` if the module fails to validate, which should never happen. /// Returns `Error` if the module fails to validate, which should never happen.
pub fn module<'context>( pub fn module<'context>(
context: &'context Context, context: &'context Context,
+5 -1
View File
@@ -14,7 +14,11 @@ env_logger = { workspace = true }
revive-solidity = { path = "../solidity" } revive-solidity = { path = "../solidity" }
revive-differential = { path = "../differential" } revive-differential = { path = "../differential" }
era-compiler-llvm-context = { path = "../llvm-context" } revive-llvm-context = { path = "../llvm-context" }
revive-common = { path = "../common" }
[dev-dependencies] [dev-dependencies]
sha1 = { workspace = true } sha1 = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
rayon = { workspace = true }
+10
View File
@@ -0,0 +1,10 @@
{
"Baseline": 3944,
"Computation": 7444,
"DivisionArithmetics": 42784,
"ERC20": 56199,
"Events": 4784,
"FibonacciIterative": 6019,
"Flipper": 4392,
"SHA1": 36107
}
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; pragma solidity ^0.8;
contract Baseline { contract Baseline {
function baseline() public payable {} function baseline() public payable {}
+13
View File
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Block {
function timestamp() public view returns (uint ret) {
ret = block.timestamp;
}
function number() public view returns (uint ret) {
ret = block.number;
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; pragma solidity ^0.8;
contract Computation { contract Computation {
function triangle_number(int64 n) public pure returns (int64 sum) { function triangle_number(int64 n) public pure returns (int64 sum) {
+13
View File
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Context {
function address_this() public view returns (address ret) {
ret = address(this);
}
function caller() public view returns (address ret) {
ret = msg.sender;
}
}
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract DivisionArithmetics {
function div(uint n, uint d) public pure returns (uint q) {
assembly {
q := div(n, d)
}
}
function sdiv(int n, int d) public pure returns (int q) {
assembly {
q := sdiv(n, d)
}
}
function mod(uint n, uint d) public pure returns (uint r) {
assembly {
r := mod(n, d)
}
}
function smod(int n, int d) public pure returns (int r) {
assembly {
r := smod(n, d)
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20; pragma solidity ^0.8;
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
interface IERC20 { interface IERC20 {
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Events {
event A() anonymous;
event E(uint, uint indexed, uint indexed, uint indexed);
function emitEvent(uint topics) public {
if (topics == 0) {
emit A();
} else {
emit E(topics, 1, 2, 3);
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24; pragma solidity ^0.8;
// https://medium.com/coinmonks/fibonacci-in-solidity-8477d907e22a // https://medium.com/coinmonks/fibonacci-in-solidity-8477d907e22a
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; pragma solidity ^0.8;
contract MSize { contract MSize {
uint[] public data; uint[] public data;
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; pragma solidity ^0.8;
contract Value { contract Value {
function value() public payable returns (uint ret) { function value() public payable returns (uint ret) {
+1 -1
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; pragma solidity ^0.8;
contract Flipper { contract Flipper {
bool coin; bool coin;
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.24; pragma solidity ^0.8;
contract MStore8 { contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word) { function mStore8(uint value) public pure returns (uint256 word) {
+305 -1
View File
@@ -1,8 +1,11 @@
use alloy_primitives::U256; use alloy_primitives::{I256, U256};
use alloy_sol_types::{sol, SolCall}; use alloy_sol_types::{sol, SolCall};
use crate::mock_runtime::{CallOutput, State};
#[derive(Clone)] #[derive(Clone)]
pub struct Contract { pub struct Contract {
pub name: &'static str,
pub evm_runtime: Vec<u8>, pub evm_runtime: Vec<u8>,
pub pvm_runtime: Vec<u8>, pub pvm_runtime: Vec<u8>,
pub calldata: Vec<u8>, pub calldata: Vec<u8>,
@@ -10,6 +13,8 @@ pub struct Contract {
sol!(contract Baseline { function baseline() public payable; }); sol!(contract Baseline { function baseline() public payable; });
sol!(contract Flipper { function flip() public; });
sol!(contract Computation { sol!(contract Computation {
function odd_product(int32 n) public pure returns (int64); function odd_product(int32 n) public pure returns (int64);
function triangle_number(int64 n) public pure returns (int64 sum); function triangle_number(int64 n) public pure returns (int64 sum);
@@ -39,12 +44,100 @@ sol!(
} }
); );
sol!(
interface IERC20 {
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns (uint);
function transfer(address recipient, uint amount) external returns (bool);
function allowance(
address owner,
address spender
) external view returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
);
sol!(
contract Block {
function timestamp() public view returns (uint ret);
function number() public view returns (uint ret);
}
);
sol!(
contract Context {
function address_this() public view returns (address);
function caller() public pure returns (address);
}
);
sol!(
contract DivisionArithmetics {
function div(uint n, uint d) public pure returns (uint q);
function sdiv(int n, int d) public pure returns (int q);
function mod(uint n, uint d) public pure returns (uint r);
function smod(int n, int d) public pure returns (int r);
}
);
sol!(
contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word);
}
);
sol!(
contract Events {
event A(uint) anonymous;
event E(uint indexed, uint indexed, uint indexed);
function emitEvent(uint topics) public;
}
);
impl Contract { impl Contract {
/// Execute the contract.
///
/// Useful helper if the contract state can be ignored,
/// as it spares the deploy transaciton.
///
/// - Inserts an account with given `code` into a new state.
/// - Callee and caller account will be `Transaction::default_address()`.
/// - Sets the calldata.
/// - Doesn't execute the constructor or deploy code.
/// - Calls the "call" export on a default backend config.
pub fn execute(&self) -> (State, CallOutput) {
State::default()
.transaction()
.with_default_account(&self.pvm_runtime)
.calldata(self.calldata.clone())
.call()
}
pub fn baseline() -> Self { pub fn baseline() -> Self {
let code = include_str!("../contracts/Baseline.sol"); let code = include_str!("../contracts/Baseline.sol");
let name = "Baseline"; let name = "Baseline";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: Baseline::baselineCall::new(()).abi_encode(), calldata: Baseline::baselineCall::new(()).abi_encode(),
@@ -56,6 +149,7 @@ impl Contract {
let name = "Computation"; let name = "Computation";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: Computation::odd_productCall::new((n,)).abi_encode(), calldata: Computation::odd_productCall::new((n,)).abi_encode(),
@@ -67,6 +161,7 @@ impl Contract {
let name = "Computation"; let name = "Computation";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: Computation::triangle_numberCall::new((n,)).abi_encode(), calldata: Computation::triangle_numberCall::new((n,)).abi_encode(),
@@ -78,6 +173,7 @@ impl Contract {
let name = "FibonacciRecursive"; let name = "FibonacciRecursive";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: FibonacciRecursive::fib3Call::new((U256::from(n),)).abi_encode(), calldata: FibonacciRecursive::fib3Call::new((U256::from(n),)).abi_encode(),
@@ -89,6 +185,7 @@ impl Contract {
let name = "FibonacciIterative"; let name = "FibonacciIterative";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: FibonacciIterative::fib3Call::new((U256::from(n),)).abi_encode(), calldata: FibonacciIterative::fib3Call::new((U256::from(n),)).abi_encode(),
@@ -100,6 +197,7 @@ impl Contract {
let name = "FibonacciBinet"; let name = "FibonacciBinet";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: FibonacciBinet::fib3Call::new((U256::from(n),)).abi_encode(), calldata: FibonacciBinet::fib3Call::new((U256::from(n),)).abi_encode(),
@@ -111,9 +209,215 @@ impl Contract {
let name = "SHA1"; let name = "SHA1";
Self { Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code), evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code), pvm_runtime: crate::compile_blob(name, code),
calldata: SHA1::sha1Call::new((pre,)).abi_encode(), calldata: SHA1::sha1Call::new((pre,)).abi_encode(),
} }
} }
pub fn flipper() -> Self {
let code = include_str!("../contracts/flipper.sol");
let name = "Flipper";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: Flipper::flipCall::new(()).abi_encode(),
}
}
pub fn erc20() -> Self {
let code = include_str!("../contracts/ERC20.sol");
let name = "ERC20";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: IERC20::totalSupplyCall::new(()).abi_encode(),
}
}
pub fn block_number() -> Self {
let code = include_str!("../contracts/Block.sol");
let name = "Block";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: Block::numberCall::new(()).abi_encode(),
}
}
pub fn block_timestamp() -> Self {
let code = include_str!("../contracts/Block.sol");
let name = "Block";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: Block::timestampCall::new(()).abi_encode(),
}
}
pub fn context_address() -> Self {
let code = include_str!("../contracts/Context.sol");
let name = "Context";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: Context::address_thisCall::new(()).abi_encode(),
}
}
pub fn context_caller() -> Self {
let code = include_str!("../contracts/Context.sol");
let name = "Context";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: Context::callerCall::new(()).abi_encode(),
}
}
pub fn division_arithmetics_div(n: U256, d: U256) -> Self {
let code = include_str!("../contracts/DivisionArithmetics.sol");
let name = "DivisionArithmetics";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: DivisionArithmetics::divCall::new((n, d)).abi_encode(),
}
}
pub fn division_arithmetics_sdiv(n: I256, d: I256) -> Self {
let code = include_str!("../contracts/DivisionArithmetics.sol");
let name = "DivisionArithmetics";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: DivisionArithmetics::sdivCall::new((n, d)).abi_encode(),
}
}
pub fn division_arithmetics_mod(n: U256, d: U256) -> Self {
let code = include_str!("../contracts/DivisionArithmetics.sol");
let name = "DivisionArithmetics";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: DivisionArithmetics::modCall::new((n, d)).abi_encode(),
}
}
pub fn division_arithmetics_smod(n: I256, d: I256) -> Self {
let code = include_str!("../contracts/DivisionArithmetics.sol");
let name = "DivisionArithmetics";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: DivisionArithmetics::smodCall::new((n, d)).abi_encode(),
}
}
pub fn mstore8(value: U256) -> Self {
let code = include_str!("../contracts/mStore8.sol");
let name = "MStore8";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: MStore8::mStore8Call::new((value,)).abi_encode(),
}
}
pub fn event(topics: U256) -> Self {
let code = include_str!("../contracts/Events.sol");
let name = "Events";
Self {
name,
evm_runtime: crate::compile_evm_bin_runtime(name, code),
pvm_runtime: crate::compile_blob(name, code),
calldata: Events::emitEventCall::new((topics,)).abi_encode(),
}
}
}
#[cfg(test)]
mod tests {
use alloy_primitives::U256;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use serde::{de::Deserialize, Serialize};
use std::{collections::BTreeMap, fs::File};
use super::Contract;
#[test]
fn codesize() {
let path = "codesize.json";
let existing = File::open(path)
.map(|file| {
BTreeMap::<String, usize>::deserialize(&mut serde_json::Deserializer::from_reader(
file,
))
.expect("should be able to deserialze codesize data")
})
.ok();
let extract_code_size = |compile: fn() -> Contract| {
let contract = compile();
let contract_length = contract.pvm_runtime.len();
let size_change = existing
.as_ref()
.and_then(|map| map.get(contract.name))
.filter(|old| **old != 0)
.map(|old| {
let old = *old as f32;
let p = (contract_length as f32 - old) / old * 100.0;
format!("({p}% change from {old} bytes)",)
})
.unwrap_or_default();
println!("{}: {contract_length} bytes {size_change}", contract.name);
(contract.name, contract_length)
};
[
Contract::baseline as fn() -> Contract,
Contract::flipper as fn() -> Contract,
(|| Contract::odd_product(0)) as fn() -> Contract,
(|| Contract::fib_iterative(0)) as fn() -> Contract,
Contract::erc20 as fn() -> Contract,
(|| Contract::sha1(Vec::new())) as fn() -> Contract,
(|| Contract::division_arithmetics_div(U256::ZERO, U256::ZERO)) as fn() -> Contract,
(|| Contract::event(U256::ZERO)) as fn() -> Contract,
]
.into_par_iter()
.map(extract_code_size)
.collect::<BTreeMap<_, _>>()
.serialize(&mut serde_json::Serializer::pretty(
File::create(path).unwrap(),
))
.unwrap_or_else(|err| panic!("can not write codesize data to '{path}': {err}"));
}
} }
+34 -11
View File
@@ -1,5 +1,8 @@
use alloy_primitives::{Address, U256};
use cases::Contract; use cases::Contract;
use mock_runtime::State; use mock_runtime::{CallOutput, State};
use crate::mock_runtime::{Event, ReturnFlags};
pub mod cases; pub mod cases;
pub mod mock_runtime; pub mod mock_runtime;
@@ -53,7 +56,7 @@ pub fn compile_blob_with_options(
Default::default(), Default::default(),
None, None,
pipeline, pipeline,
era_compiler_llvm_context::OptimizerSettings::cycles(), revive_llvm_context::OptimizerSettings::cycles(),
solc_optimizer_enabled, solc_optimizer_enabled,
) )
.expect("source should compile") .expect("source should compile")
@@ -64,22 +67,42 @@ pub fn compile_blob_with_options(
.evm .evm
.as_ref() .as_ref()
.expect("source should produce EVM output") .expect("source should produce EVM output")
.assembly_text .bytecode
.as_ref() .as_ref()
.expect("source should produce assembly text"); .expect("source should produce assembly text")
.object
.as_str();
hex::decode(bytecode).expect("hex encoding should always be valid") hex::decode(bytecode).expect("hex encoding should always be valid")
} }
pub fn assert_success(contract: Contract, differential: bool) -> State { pub fn assert_success(contract: &Contract, differential: bool) -> (State, CallOutput) {
let (mut instance, export) = mock_runtime::prepare(&contract.pvm_runtime, None); let (state, output) = contract.execute();
let state = mock_runtime::call(State::new(contract.calldata.clone()), &mut instance, export); assert_eq!(output.flags, ReturnFlags::Success);
assert_eq!(state.output.flags, 0);
if differential { if differential {
let evm = revive_differential::prepare(contract.evm_runtime, contract.calldata); let evm =
assert_eq!(state.output.data.clone(), revive_differential::execute(evm)); revive_differential::prepare(contract.evm_runtime.clone(), contract.calldata.clone());
let (evm_output, evm_log) = revive_differential::execute(evm);
assert_eq!(output.data.clone(), evm_output);
assert_eq!(output.events.len(), evm_log.len());
assert_eq!(
output.events,
evm_log
.iter()
.map(|log| Event {
address: Address::from_slice(log.address.as_bytes()),
data: log.data.clone(),
topics: log
.topics
.iter()
.map(|topic| U256::from_be_bytes(topic.0))
.collect(),
})
.collect::<Vec<_>>()
);
} }
state (state, output)
} }
+482 -76
View File
@@ -1,66 +1,339 @@
//! Mock environment used for integration tests. //! Mock environment used for integration tests.
//! TODO: Switch to drink! once RISCV is ready in polkadot-sdk
use std::collections::HashMap; use std::collections::HashMap;
use alloy_primitives::{Keccak256, U256}; use alloy_primitives::{keccak256, Address, Keccak256, B256, U256};
use polkavm::{ use polkavm::{
Caller, Config, Engine, ExportIndex, GasMeteringKind, Instance, Linker, Module, ModuleConfig, Caller, Config, Engine, ExportIndex, GasMeteringKind, Instance, Linker, Module, ModuleConfig,
ProgramBlob, Trap, ProgramBlob, Trap,
}; };
use revive_llvm_context::polkavm_const::runtime_api;
#[derive(Default, Clone, Debug)] /// The mocked blockchain account.
pub struct State { #[derive(Debug, Default, Clone)]
pub input: Vec<u8>, struct Account {
pub output: CallOutput, value: U256,
pub value: u128, contract: Option<U256>,
pub storage: HashMap<U256, U256>, storage: HashMap<U256, U256>,
} }
#[derive(Clone, Debug)] /// Emitted event data.
pub struct CallOutput { #[derive(Debug, Default, Clone, PartialEq)]
pub flags: u32, pub struct Event {
pub address: Address,
pub data: Vec<u8>, pub data: Vec<u8>,
pub topics: Vec<U256>,
} }
impl Default for CallOutput { /// The result of the contract call.
fn default() -> Self { #[derive(Debug, Default, Clone)]
Self { pub struct CallOutput {
flags: u32::MAX, /// The return flags.
data: Vec::new(), pub flags: ReturnFlags,
/// The contract call output.
pub data: Vec<u8>,
/// The emitted events.
pub events: Vec<Event>,
}
/// The contract blob export to be called.
#[derive(Clone, Debug, Default)]
enum Export {
#[default]
Call,
Deploy(U256),
}
/// Possible contract call return flags.
#[derive(Debug, Default, Clone, PartialEq)]
#[repr(u32)]
pub enum ReturnFlags {
/// The contract execution returned normally.
Success = 0,
/// The contract execution returned normally but state changes should be reverted.
Revert = 1,
/// The contract trapped unexpectedly during execution.
#[default]
Trap = u32::MAX,
}
impl From<u32> for ReturnFlags {
fn from(value: u32) -> Self {
match value {
0 => Self::Success,
1 => Self::Revert,
u32::MAX => Self::Trap,
_ => panic!("invalid return flag: {value}"),
} }
} }
} }
/// The local context inside the call stack.
#[derive(Debug, Clone)]
struct Frame {
/// The account that is being executed.
callee: Address,
/// The caller account.
caller: Address,
/// The value transferred with this transaction.
callvalue: U256,
/// The calldata for the contract execution.
input: Vec<u8>,
// The contract call output.
output: CallOutput,
/// The export to call.
export: Export,
}
impl Default for Frame {
fn default() -> Self {
Self {
callee: Transaction::default_address(),
caller: Transaction::default_address(),
callvalue: Default::default(),
input: Default::default(),
output: Default::default(),
export: Default::default(),
}
}
}
/// The transaction can modify the state by calling contracts.
///
/// Use the [TransactionBuilder] to create new transactions.
#[derive(Default, Clone, Debug)]
pub struct Transaction {
state: State,
stack: Vec<Frame>,
}
impl Transaction {
pub fn default_address() -> Address {
Address::default().create2(B256::default(), keccak256([]).0)
}
fn top_frame(&self) -> &Frame {
self.stack.last().expect("transactions should have a frame")
}
fn top_frame_mut(&mut self) -> &mut Frame {
self.stack
.last_mut()
.expect("transactions should have a frame")
}
fn top_account_mut(&mut self) -> &mut Account {
let account = self.top_frame_mut().callee;
self.state
.accounts
.get_mut(&account)
.unwrap_or_else(|| panic!("callee has no associated account: {account}"))
}
fn create2(&self, salt: U256, blob_hash: U256) -> Address {
self.top_frame()
.callee
.create2(salt.to_be_bytes(), blob_hash.to_be_bytes())
}
}
/// Helper to create valid transactions.
#[derive(Default, Clone, Debug)]
pub struct TransactionBuilder {
context: Transaction,
state_before: State,
}
impl TransactionBuilder {
/// Set the caller account.
pub fn caller(mut self, account: Address) -> Self {
self.context.top_frame_mut().caller = account;
self
}
/// Set the callee account.
pub fn callee(mut self, account: Address) -> Self {
self.context.top_frame_mut().callee = account;
self
}
/// Set the transferred callvalue.
pub fn callvalue(mut self, amount: U256) -> Self {
self.context.top_frame_mut().callvalue = amount;
self
}
/// Set the calldata.
pub fn calldata(mut self, data: Vec<u8>) -> Self {
self.context.top_frame_mut().input = data;
self
}
/// Set the transaction to deploy code.
pub fn deploy(mut self, code: &[u8]) -> Self {
let blob_hash = self.context.state.upload_code(code);
self.context.top_frame_mut().export = Export::Deploy(blob_hash);
self
}
/// Set the account at [Transaction::default_address] to the given `code`.
///
/// Useful helper to spare the deploy transaction.
pub fn with_default_account(mut self, code: &[u8]) -> Self {
self.context.state.upload_code(code);
self.context.state.create_account(
Transaction::default_address(),
Default::default(),
keccak256(code).into(),
);
self
}
/// Execute the transaction with a default config backend.
///
/// Reverts any state changes if the contract reverts or the exuection traps.
pub fn call(mut self) -> (State, CallOutput) {
let blob_hash = match self.context.top_frame().export {
Export::Call => self.context.top_account_mut().contract.unwrap_or_else(|| {
panic!(
"not a contract account: {}",
self.context.top_frame().callee
)
}),
Export::Deploy(blob_hash) => blob_hash,
};
let code = self
.context
.state
.blobs
.get(&blob_hash)
.unwrap_or_else(|| panic!("contract code not found: {blob_hash}"));
let (mut instance, export) = prepare(code, None);
self.call_on(&mut instance, export)
}
/// Execute the transaction on a given instance and export.
/// The `instance` and `export` are expected to match that of the `Transaction`.
/// Reverts any state changes if the contract reverts or the exuection traps.
pub fn call_on(
mut self,
instance: &mut Instance<Transaction>,
export: ExportIndex,
) -> (State, CallOutput) {
let mut state_args = polkavm::StateArgs::default();
state_args.set_gas(polkavm::Gas::MAX);
if let Export::Deploy(blob_hash) = self.context.top_frame().export {
self.context.state.create_account(
self.context.create2(Default::default(), blob_hash),
self.context.top_frame().callvalue,
blob_hash,
);
}
let callvalue = self.context.top_frame().callvalue;
self.context.top_account_mut().value += callvalue;
let call_args = polkavm::CallArgs::new(&mut self.context, export);
init_logs();
match instance.call(state_args, call_args) {
Err(polkavm::ExecutionError::Trap(_)) => self.finalize(),
Err(other) => panic!("unexpected error: {other}"),
Ok(_) => panic!("unexpected return"),
}
}
/// Commits or reverts the state changes based on the call flags.
fn finalize(mut self) -> (State, CallOutput) {
let state = match self.context.top_frame().output.flags {
ReturnFlags::Success => self.context.state,
_ => self.state_before,
};
let output = self.context.stack.pop().unwrap().output;
(state, output)
}
}
impl From<State> for TransactionBuilder {
fn from(state: State) -> Self {
TransactionBuilder {
state_before: state.clone(),
context: Transaction {
state,
stack: Default::default(),
},
}
}
}
/// The mocked blockchain state.
#[derive(Default, Clone, Debug)]
pub struct State {
blobs: HashMap<U256, Vec<u8>>,
accounts: HashMap<Address, Account>,
}
impl State { impl State {
pub fn new(input: Vec<u8>) -> Self { pub const BLOCK_NUMBER: u64 = 123;
Self { pub const BLOCK_TIMESTAMP: u64 = 456;
input,
..Default::default() pub fn transaction(self) -> TransactionBuilder {
TransactionBuilder {
state_before: self.clone(),
context: Transaction {
state: self,
stack: vec![Default::default()],
},
} }
} }
pub fn reset_output(&mut self) { pub fn upload_code(&mut self, code: &[u8]) -> U256 {
self.output = Default::default(); let blob_hash = keccak256(code).into();
self.blobs.insert(blob_hash, code.to_vec());
blob_hash
} }
pub fn assert_storage_key(&self, at: U256, expect: U256) { pub fn assert_storage_key(&self, account: Address, key: U256, expected: U256) {
assert_eq!(self.storage[&at], expect); assert_eq!(
self.accounts
.get(&account)
.unwrap_or_else(|| panic!("unknown account: {account}"))
.storage
.get(&key)
.copied()
.unwrap_or_default(),
expected
);
}
pub fn create_account(&mut self, address: Address, value: U256, blob_hash: U256) {
self.accounts.insert(
address,
Account {
value,
contract: Some(blob_hash),
storage: HashMap::new(),
},
);
} }
} }
fn link_host_functions(engine: &Engine) -> Linker<State> { fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
let mut linker = Linker::new(engine); let mut linker = Linker::new(engine);
linker linker
.func_wrap( .func_wrap(
"input", runtime_api::INPUT,
|caller: Caller<State>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> { |caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
let (mut caller, state) = caller.split(); let (mut caller, transaction) = caller.split();
assert!(state.input.len() <= caller.read_u32(out_len_ptr).unwrap() as usize); let input = &transaction.top_frame().input;
assert!(input.len() <= caller.read_u32(out_len_ptr).unwrap() as usize);
caller.write_memory(out_ptr, &state.input)?; caller.write_memory(out_ptr, input)?;
caller.write_memory(out_len_ptr, &(state.input.len() as u32).to_le_bytes())?; caller.write_memory(out_len_ptr, &(input.len() as u32).to_le_bytes())?;
Ok(()) Ok(())
}, },
@@ -69,12 +342,17 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
linker linker
.func_wrap( .func_wrap(
"seal_return", runtime_api::RETURN,
|caller: Caller<State>, flags: u32, data_ptr: u32, data_len: u32| -> Result<(), Trap> { |caller: Caller<Transaction>,
let (caller, state) = caller.split(); flags: u32,
data_ptr: u32,
data_len: u32|
-> Result<(), Trap> {
let (caller, transaction) = caller.split();
state.output.flags = flags; let frame = transaction.top_frame_mut();
state.output.data = caller.read_memory_into_vec(data_ptr, data_len)?; frame.output.flags = flags.into();
frame.output.data = caller.read_memory_into_vec(data_ptr, data_len)?;
Err(Default::default()) Err(Default::default())
}, },
@@ -83,12 +361,18 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
linker linker
.func_wrap( .func_wrap(
"value_transferred", runtime_api::VALUE_TRANSFERRED,
|caller: Caller<State>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> { |caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> {
let (mut caller, state) = caller.split(); let (mut caller, transaction) = caller.split();
let value = state.value.to_le_bytes(); let out_len = caller.read_u32(out_len_ptr)? as usize;
assert_eq!(
out_len,
revive_common::BYTE_LENGTH_VALUE,
"spurious output buffer size: {out_len}"
);
let value = transaction.top_frame().callvalue.as_le_bytes();
caller.write_memory(out_ptr, &value)?; caller.write_memory(out_ptr, &value)?;
caller.write_memory(out_len_ptr, &(value.len() as u32).to_le_bytes())?; caller.write_memory(out_len_ptr, &(value.len() as u32).to_le_bytes())?;
@@ -100,7 +384,7 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
linker linker
.func_wrap( .func_wrap(
"debug_message", "debug_message",
|caller: Caller<State>, str_ptr: u32, str_len: u32| -> Result<u32, Trap> { |caller: Caller<Transaction>, str_ptr: u32, str_len: u32| -> Result<u32, Trap> {
let (caller, _) = caller.split(); let (caller, _) = caller.split();
let data = caller.read_memory_into_vec(str_ptr, str_len)?; let data = caller.read_memory_into_vec(str_ptr, str_len)?;
@@ -113,22 +397,30 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
linker linker
.func_wrap( .func_wrap(
"set_storage", runtime_api::SET_STORAGE,
|caller: Caller<State>, |caller: Caller<Transaction>,
key_ptr: u32, key_ptr: u32,
key_len: u32, key_len: u32,
value_ptr: u32, value_ptr: u32,
value_len: u32| value_len: u32|
-> Result<u32, Trap> { -> Result<u32, Trap> {
let (caller, state) = caller.split(); let (caller, transaction) = caller.split();
assert_eq!(key_len, 32, "storage key must be 32 bytes"); assert_eq!(
assert_eq!(value_len, 32, "storage value must be 32 bytes"); key_len as usize,
revive_common::BYTE_LENGTH_WORD,
"storage key must be 32 bytes"
);
assert_eq!(
value_len as usize,
revive_common::BYTE_LENGTH_WORD,
"storage value must be 32 bytes"
);
let key = caller.read_memory_into_vec(key_ptr, key_len)?; let key = caller.read_memory_into_vec(key_ptr, key_len)?;
let value = caller.read_memory_into_vec(value_ptr, value_len)?; let value = caller.read_memory_into_vec(value_ptr, value_len)?;
state.storage.insert( transaction.top_account_mut().storage.insert(
U256::from_be_bytes::<32>(key.try_into().unwrap()), U256::from_be_bytes::<32>(key.try_into().unwrap()),
U256::from_be_bytes::<32>(value.try_into().unwrap()), U256::from_be_bytes::<32>(value.try_into().unwrap()),
); );
@@ -140,20 +432,25 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
linker linker
.func_wrap( .func_wrap(
"get_storage", runtime_api::GET_STORAGE,
|caller: Caller<State>, |caller: Caller<Transaction>,
key_ptr: u32, key_ptr: u32,
key_len: u32, key_len: u32,
out_ptr: u32, out_ptr: u32,
out_len_ptr: u32| out_len_ptr: u32|
-> Result<u32, Trap> { -> Result<u32, Trap> {
let (mut caller, state) = caller.split(); let (mut caller, transaction) = caller.split();
let key = caller.read_memory_into_vec(key_ptr, key_len)?; let key = caller.read_memory_into_vec(key_ptr, key_len)?;
let out_len = caller.read_u32(out_len_ptr)?; let out_len = caller.read_u32(out_len_ptr)? as usize;
assert!(out_len >= 32); assert_eq!(
out_len,
revive_common::BYTE_LENGTH_WORD,
"spurious output buffer size: {out_len}"
);
let value = state let value = transaction
.top_account_mut()
.storage .storage
.get(&U256::from_be_bytes::<32>(key.try_into().unwrap())) .get(&U256::from_be_bytes::<32>(key.try_into().unwrap()))
.map(U256::to_be_bytes::<32>) .map(U256::to_be_bytes::<32>)
@@ -169,8 +466,8 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
linker linker
.func_wrap( .func_wrap(
"hash_keccak_256", runtime_api::HASH_KECCAK_256,
|caller: Caller<State>, |caller: Caller<Transaction>,
input_ptr: u32, input_ptr: u32,
input_len: u32, input_len: u32,
out_ptr: u32| out_ptr: u32|
@@ -188,6 +485,129 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
) )
.unwrap(); .unwrap();
linker
.func_wrap(
runtime_api::NOW,
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
let (mut caller, _) = caller.split();
let out_len = caller.read_u32(out_len_ptr)? as usize;
assert_eq!(
out_len,
revive_common::BYTE_LENGTH_BLOCK_TIMESTAMP,
"spurious output buffer size: {out_len}"
);
caller.write_memory(out_ptr, &State::BLOCK_TIMESTAMP.to_le_bytes())?;
caller.write_memory(out_len_ptr, &64u32.to_le_bytes())?;
Ok(())
},
)
.unwrap();
linker
.func_wrap(
runtime_api::BLOCK_NUMBER,
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
let (mut caller, _) = caller.split();
let out_len = caller.read_u32(out_len_ptr)? as usize;
assert_eq!(
out_len,
revive_common::BYTE_LENGTH_BLOCK_NUMBER,
"spurious output buffer size: {out_len}"
);
caller.write_memory(out_ptr, &State::BLOCK_NUMBER.to_le_bytes())?;
caller.write_memory(out_len_ptr, &64u32.to_le_bytes())?;
Ok(())
},
)
.unwrap();
linker
.func_wrap(
runtime_api::ADDRESS,
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
let (mut caller, transaction) = caller.split();
let out_len = caller.read_u32(out_len_ptr)? as usize;
assert_eq!(
out_len,
revive_common::BYTE_LENGTH_ETH_ADDRESS,
"spurious output buffer size: {out_len}"
);
let address = transaction.top_frame().callee.as_slice();
caller.write_memory(out_ptr, address)?;
caller.write_memory(out_len_ptr, &(address.len() as u32).to_le_bytes())?;
Ok(())
},
)
.unwrap();
linker
.func_wrap(
runtime_api::CALLER,
|caller: Caller<Transaction>, out_ptr: u32, out_len_ptr: u32| {
let (mut caller, transaction) = caller.split();
let out_len = caller.read_u32(out_len_ptr)? as usize;
assert_eq!(
out_len,
revive_common::BYTE_LENGTH_ETH_ADDRESS,
"spurious output buffer size: {out_len}"
);
let address = transaction.top_frame().caller.as_slice();
caller.write_memory(out_ptr, address)?;
caller.write_memory(out_len_ptr, &(address.len() as u32).to_le_bytes())?;
Ok(())
},
)
.unwrap();
linker
.func_wrap(
runtime_api::DEPOSIT_EVENT,
|caller: Caller<Transaction>,
topics_ptr: u32,
topics_len: u32,
data_ptr: u32,
data_len: u32| {
let (caller, transaction) = caller.split();
let address = transaction.top_frame().callee;
let data = if data_len != 0 {
caller.read_memory_into_vec(data_ptr, data_len)?
} else {
Default::default()
};
let topics = if topics_len != 0 {
caller
.read_memory_into_vec(topics_ptr, topics_len)?
.chunks(32)
.map(|chunk| U256::from_be_slice(chunk))
.collect()
} else {
Default::default()
};
transaction.top_frame_mut().output.events.push(Event {
address,
data,
topics,
});
Ok(())
},
)
.unwrap();
linker linker
} }
@@ -202,15 +622,18 @@ pub fn recompile_code(code: &[u8], engine: &Engine) -> Module {
Module::new(engine, &module_config, code).unwrap() Module::new(engine, &module_config, code).unwrap()
} }
pub fn instantiate_module(module: &Module, engine: &Engine) -> (Instance<State>, ExportIndex) { pub fn instantiate_module(
let export = module.lookup_export("call").unwrap(); module: &Module,
engine: &Engine,
) -> (Instance<Transaction>, ExportIndex) {
let export = module.lookup_export(runtime_api::CALL).unwrap();
let func = link_host_functions(engine).instantiate_pre(module).unwrap(); let func = link_host_functions(engine).instantiate_pre(module).unwrap();
let instance = func.instantiate().unwrap(); let instance = func.instantiate().unwrap();
(instance, export) (instance, export)
} }
pub fn prepare(code: &[u8], config: Option<Config>) -> (Instance<State>, ExportIndex) { pub fn prepare(code: &[u8], config: Option<Config>) -> (Instance<Transaction>, ExportIndex) {
let blob = ProgramBlob::parse(code).unwrap(); let blob = ProgramBlob::parse(code).unwrap();
let engine = Engine::new(&config.unwrap_or_default()).unwrap(); let engine = Engine::new(&config.unwrap_or_default()).unwrap();
@@ -219,7 +642,7 @@ pub fn prepare(code: &[u8], config: Option<Config>) -> (Instance<State>, ExportI
module_config.set_gas_metering(Some(GasMeteringKind::Sync)); module_config.set_gas_metering(Some(GasMeteringKind::Sync));
let module = Module::from_blob(&engine, &module_config, &blob).unwrap(); let module = Module::from_blob(&engine, &module_config, &blob).unwrap();
let export = module.lookup_export("call").unwrap(); let export = module.lookup_export(runtime_api::CALL).unwrap();
let func = link_host_functions(&engine) let func = link_host_functions(&engine)
.instantiate_pre(&module) .instantiate_pre(&module)
.unwrap(); .unwrap();
@@ -228,23 +651,6 @@ pub fn prepare(code: &[u8], config: Option<Config>) -> (Instance<State>, ExportI
(instance, export) (instance, export)
} }
pub fn call(mut state: State, on: &mut Instance<State>, export: ExportIndex) -> State {
state.reset_output();
let mut state_args = polkavm::StateArgs::default();
state_args.set_gas(polkavm::Gas::MAX);
let call_args = polkavm::CallArgs::new(&mut state, export);
init_logs();
match on.call(state_args, call_args) {
Err(polkavm::ExecutionError::Trap(_)) => state,
Err(other) => panic!("unexpected error: {other}"),
Ok(_) => panic!("unexpected return"),
}
}
fn init_logs() { fn init_logs() {
if std::env::var("RUST_LOG").is_ok() { if std::env::var("RUST_LOG").is_ok() {
#[cfg(test)] #[cfg(test)]
+220 -64
View File
@@ -1,11 +1,12 @@
use alloy_primitives::{FixedBytes, Keccak256, I256, U256}; use alloy_primitives::{keccak256, Address, FixedBytes, I256, U256};
use alloy_sol_types::{sol, SolCall}; use alloy_sol_types::{sol, SolCall};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use sha1::Digest; use sha1::Digest;
use crate::{ use crate::{
assert_success, assert_success,
cases::Contract, cases::Contract,
mock_runtime::{self, State}, mock_runtime::{self, ReturnFlags, State, Transaction},
}; };
#[test] #[test]
@@ -17,8 +18,8 @@ fn fibonacci() {
Contract::fib_iterative(parameter), Contract::fib_iterative(parameter),
Contract::fib_binet(parameter), Contract::fib_binet(parameter),
] { ] {
let state = assert_success(contract, true); let (_, output) = assert_success(&contract, true);
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
let expected = U256::from(8); let expected = U256::from(8);
assert_eq!(received, expected); assert_eq!(received, expected);
} }
@@ -26,17 +27,16 @@ fn fibonacci() {
#[test] #[test]
fn flipper() { fn flipper() {
let code = crate::compile_blob("Flipper", include_str!("../contracts/flipper.sol")); let contract = Contract::flipper();
let state = State::new(0xcde4efa9u32.to_be_bytes().to_vec()); let address = Transaction::default_address();
let (mut instance, export) = mock_runtime::prepare(&code, None);
let state = crate::mock_runtime::call(state, &mut instance, export); let (state, output) = contract.execute();
assert_eq!(state.output.flags, 0); assert_eq!(output.flags, ReturnFlags::Success);
assert_eq!(state.storage[&U256::ZERO], U256::try_from(1).unwrap()); state.assert_storage_key(address, U256::ZERO, U256::from(1));
let state = crate::mock_runtime::call(state, &mut instance, export); let (state, output) = state.transaction().calldata(contract.calldata).call();
assert_eq!(state.output.flags, 0); assert_eq!(output.flags, ReturnFlags::Success);
assert_eq!(state.storage[&U256::ZERO], U256::ZERO); state.assert_storage_key(address, U256::ZERO, U256::ZERO);
} }
#[test] #[test]
@@ -57,16 +57,16 @@ fn hash_keccak_256() {
let param = "hello"; let param = "hello";
let input = TestSha3::testCall::new((param.to_string(),)).abi_encode(); let input = TestSha3::testCall::new((param.to_string(),)).abi_encode();
let state = State::new(input); let (_, output) = State::default()
let (mut instance, export) = mock_runtime::prepare(&code, None); .transaction()
let state = crate::mock_runtime::call(state, &mut instance, export); .with_default_account(&code)
.calldata(input)
.call();
assert_eq!(state.output.flags, 0); assert_eq!(output.flags, ReturnFlags::Success);
let mut hasher = Keccak256::new(); let expected = keccak256(param.as_bytes());
hasher.update(param); let received = FixedBytes::<32>::from_slice(&output.data);
let expected = hasher.finalize();
let received = FixedBytes::<32>::from_slice(&state.output.data);
assert_eq!(received, expected); assert_eq!(received, expected);
} }
@@ -77,16 +77,16 @@ fn erc20() {
#[test] #[test]
fn triangle_number() { fn triangle_number() {
let state = assert_success(Contract::triangle_number(13), true); let (_, output) = assert_success(&Contract::triangle_number(13), true);
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
let expected = U256::try_from(91).unwrap(); let expected = U256::try_from(91).unwrap();
assert_eq!(received, expected); assert_eq!(received, expected);
} }
#[test] #[test]
fn odd_product() { fn odd_product() {
let state = assert_success(Contract::odd_product(5), true); let (_, output) = assert_success(&Contract::odd_product(5), true);
let received = I256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); let received = I256::from_be_bytes::<32>(output.data.try_into().unwrap());
let expected = I256::try_from(945i64).unwrap(); let expected = I256::try_from(945i64).unwrap();
assert_eq!(received, expected); assert_eq!(received, expected);
} }
@@ -105,16 +105,19 @@ fn msize_plain() {
false, false,
revive_solidity::SolcPipeline::EVMLA, revive_solidity::SolcPipeline::EVMLA,
); );
let (mut instance, export) = mock_runtime::prepare(&code, None);
let input = MSize::mSizeCall::new(()).abi_encode(); let input = MSize::mSizeCall::new(()).abi_encode();
let state = crate::mock_runtime::call(State::new(input), &mut instance, export); let (_, output) = State::default()
.transaction()
.calldata(input)
.with_default_account(&code)
.call();
assert_eq!(state.output.flags, 0); assert_eq!(output.flags, ReturnFlags::Success);
// Solidity always stores the "free memory pointer" (32 byte int) at offset 64. // Solidity always stores the "free memory pointer" (32 byte int) at offset 64.
let expected = U256::try_from(64 + 32).unwrap(); let expected = U256::try_from(64 + 32).unwrap();
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
assert_eq!(received, expected); assert_eq!(received, expected);
} }
@@ -126,16 +129,18 @@ fn transferred_value() {
} }
); );
let code = crate::compile_blob("Value", include_str!("../contracts/Value.sol")); let code = crate::compile_blob("Value", include_str!("../contracts/Value.sol"));
let mut state = State::new(Value::valueCall::SELECTOR.to_vec());
state.value = 0x1;
let (mut instance, export) = mock_runtime::prepare(&code, None); let (_, output) = State::default()
let state = crate::mock_runtime::call(state, &mut instance, export); .transaction()
.calldata(Value::valueCall::SELECTOR.to_vec())
.callvalue(U256::from(123))
.with_default_account(&code)
.call();
assert_eq!(state.output.flags, 0); assert_eq!(output.flags, ReturnFlags::Success);
let expected = I256::try_from(state.value).unwrap(); let expected = I256::try_from(123).unwrap();
let received = I256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); let received = I256::from_be_bytes::<32>(output.data.try_into().unwrap());
assert_eq!(received, expected); assert_eq!(received, expected);
} }
@@ -153,43 +158,27 @@ fn msize_non_word_sized_access() {
false, false,
revive_solidity::SolcPipeline::Yul, revive_solidity::SolcPipeline::Yul,
); );
let (mut instance, export) = mock_runtime::prepare(&code, None);
let input = MSize::mStore100Call::new(()).abi_encode(); let input = MSize::mStore100Call::new(()).abi_encode();
let state = crate::mock_runtime::call(State::new(input), &mut instance, export); let (_, output) = State::default()
.transaction()
.with_default_account(&code)
.calldata(input)
.call();
assert_eq!(state.output.flags, 0); assert_eq!(output.flags, ReturnFlags::Success);
// https://docs.zksync.io/build/developer-reference/differences-with-ethereum.html#mstore-mload // https://docs.zksync.io/build/developer-reference/differences-with-ethereum.html#mstore-mload
// "Unlike EVM, where the memory growth is in words, on zkEVM the memory growth is counted in bytes." // "Unlike EVM, where the memory growth is in words, on zkEVM the memory growth is counted in bytes."
// "For example, if you write mstore(100, 0) the msize on zkEVM will be 132, but on the EVM it will be 160." // "For example, if you write mstore(100, 0) the msize on zkEVM will be 132, but on the EVM it will be 160."
let expected = U256::try_from(132).unwrap(); let expected = U256::try_from(132).unwrap();
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
assert_eq!(received, expected); assert_eq!(received, expected);
} }
#[test] #[test]
fn mstore8() { fn mstore8() {
sol!( for (received, expected) in [
#[derive(Debug, PartialEq, Eq)]
contract MStore8 {
function mStore8(uint value) public pure returns (uint256 word);
}
);
let code = crate::compile_blob("MStore8", include_str!("../contracts/mStore8.sol"));
let (mut instance, export) = mock_runtime::prepare(&code, None);
let mut assert = |parameter, expected| {
let input = MStore8::mStore8Call::new((parameter,)).abi_encode();
let state = crate::mock_runtime::call(State::new(input), &mut instance, export);
assert_eq!(state.output.flags, 0);
let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap());
assert_eq!(received, expected);
};
for (parameter, expected) in [
(U256::MIN, U256::MIN), (U256::MIN, U256::MIN),
( (
U256::from(1), U256::from(1),
@@ -248,8 +237,16 @@ fn mstore8() {
) )
.unwrap(), .unwrap(),
), ),
] { ]
assert(parameter, expected); .par_iter()
.map(|(parameter, expected)| {
let (_, output) = assert_success(&Contract::mstore8(*parameter), true);
let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
(received, *expected)
})
.collect::<Vec<_>>()
{
assert_eq!(received, expected);
} }
} }
@@ -260,8 +257,167 @@ fn sha1() {
hasher.update(&pre); hasher.update(&pre);
let hash = hasher.finalize(); let hash = hasher.finalize();
let state = assert_success(Contract::sha1(pre), true); let (_, output) = assert_success(&Contract::sha1(pre), true);
let expected = FixedBytes::<20>::from_slice(&hash[..]); let expected = FixedBytes::<20>::from_slice(&hash[..]);
let received = FixedBytes::<20>::from_slice(&state.output.data[..20]); let received = FixedBytes::<20>::from_slice(&output.data[..20]);
assert_eq!(received, expected); assert_eq!(received, expected);
} }
#[test]
fn block_number() {
let (_, output) = assert_success(&Contract::block_number(), true);
let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
let expected = U256::from(mock_runtime::State::BLOCK_NUMBER);
assert_eq!(received, expected);
}
#[test]
fn block_timestamp() {
let (_, output) = assert_success(&Contract::block_timestamp(), true);
let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
let expected = U256::from(mock_runtime::State::BLOCK_TIMESTAMP);
assert_eq!(received, expected);
}
#[test]
fn address() {
let contract = Contract::context_address();
let (_, output) = assert_success(&contract, true);
let received = Address::from_slice(&output.data[12..]);
let expected = Transaction::default_address();
assert_eq!(received, expected);
}
#[test]
fn caller() {
let (_, output) = assert_success(&Contract::context_caller(), true);
let received = Address::from_slice(&output.data[12..]);
let expected = Transaction::default_address();
assert_eq!(received, expected);
}
#[test]
fn unsigned_division() {
let one = U256::from(1);
let two = U256::from(2);
let five = U256::from(5);
for (received, expected) in [
(five, five, one),
(five, one, five),
(U256::ZERO, U256::MAX, U256::ZERO),
(five, two, two),
(one, U256::ZERO, U256::ZERO),
]
.par_iter()
.map(|(n, d, q)| {
let (_, output) = assert_success(&Contract::division_arithmetics_div(*n, *d), true);
let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
(received, *q)
})
.collect::<Vec<_>>()
{
assert_eq!(received, expected)
}
}
#[test]
fn signed_division() {
let one = I256::try_from(1).unwrap();
let two = I256::try_from(2).unwrap();
let minus_two = I256::try_from(-2).unwrap();
let five = I256::try_from(5).unwrap();
let minus_five = I256::try_from(-5).unwrap();
for (received, expected) in [
(five, five, one),
(five, one, five),
(I256::ZERO, I256::MAX, I256::ZERO),
(I256::ZERO, I256::MINUS_ONE, I256::ZERO),
(five, two, two),
(five, I256::MINUS_ONE, minus_five),
(I256::MINUS_ONE, minus_two, I256::ZERO),
(minus_five, minus_five, one),
(minus_five, two, minus_two),
(I256::MINUS_ONE, I256::MIN, I256::ZERO),
(one, I256::ZERO, I256::ZERO),
]
.par_iter()
.map(|(n, d, q)| {
let (_, output) = assert_success(&Contract::division_arithmetics_sdiv(*n, *d), true);
let received = I256::from_be_bytes::<32>(output.data.try_into().unwrap());
(received, *q)
})
.collect::<Vec<_>>()
{
assert_eq!(received, expected);
}
}
#[test]
fn unsigned_remainder() {
let one = U256::from(1);
let two = U256::from(2);
let five = U256::from(5);
for (received, expected) in [
(five, five, U256::ZERO),
(five, one, U256::ZERO),
(U256::ZERO, U256::MAX, U256::ZERO),
(U256::MAX, U256::MAX, U256::ZERO),
(five, two, one),
(two, five, two),
(U256::MAX, U256::ZERO, U256::ZERO),
]
.par_iter()
.map(|(n, d, q)| {
let (_, output) = assert_success(&Contract::division_arithmetics_mod(*n, *d), true);
let received = U256::from_be_bytes::<32>(output.data.try_into().unwrap());
(received, *q)
})
.collect::<Vec<_>>()
{
assert_eq!(received, expected);
}
}
#[test]
fn signed_remainder() {
let one = I256::try_from(1).unwrap();
let two = I256::try_from(2).unwrap();
let minus_two = I256::try_from(-2).unwrap();
let five = I256::try_from(5).unwrap();
let minus_five = I256::try_from(-5).unwrap();
for (received, expected) in [
(five, five, I256::ZERO),
(five, one, I256::ZERO),
(I256::ZERO, I256::MAX, I256::ZERO),
(I256::MAX, I256::MAX, I256::ZERO),
(five, two, one),
(two, five, two),
(five, minus_five, I256::ZERO),
(five, I256::MINUS_ONE, I256::ZERO),
(five, minus_two, one),
(minus_five, two, I256::MINUS_ONE),
(minus_two, five, minus_two),
(minus_five, minus_five, I256::ZERO),
(minus_five, I256::MINUS_ONE, I256::ZERO),
(minus_five, minus_two, I256::MINUS_ONE),
(minus_two, minus_five, minus_two),
(I256::MIN, I256::MINUS_ONE, I256::ZERO),
(I256::ZERO, I256::ZERO, I256::ZERO),
]
.par_iter()
.map(|(n, d, q)| {
let (_, output) = assert_success(&Contract::division_arithmetics_smod(*n, *d), true);
let received = I256::from_be_bytes::<32>(output.data.try_into().unwrap());
(received, *q)
})
.collect::<Vec<_>>()
{
assert_eq!(received, expected);
}
}
#[test]
fn events() {
assert_success(&Contract::event(U256::ZERO), true);
assert_success(&Contract::event(U256::from(123)), true);
}
+7 -3
View File
@@ -1,5 +1,5 @@
[package] [package]
name = "era-compiler-llvm-context" name = "revive-llvm-context"
version = "1.4.1" version = "1.4.1"
authors = [ authors = [
"Oleksandr Zarudnyi <a.zarudnyy@matterlabs.dev>", "Oleksandr Zarudnyi <a.zarudnyy@matterlabs.dev>",
@@ -7,11 +7,14 @@ authors = [
] ]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2021" edition = "2021"
description = "Shared front end code of the EraVM compilers" description = "Shared front end code of the revive PolkaVM compilers"
[lib] [lib]
doctest = false doctest = false
[features]
riscv-zbb = []
[dependencies] [dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
semver = { workspace = true } semver = { workspace = true }
@@ -25,6 +28,8 @@ sha2 = { workspace = true }
sha3 = { workspace = true } sha3 = { workspace = true }
md5 = { workspace = true } md5 = { workspace = true }
inkwell = { workspace = true } inkwell = { workspace = true }
polkavm-disassembler = { workspace = true }
polkavm-common = { workspace = true }
zkevm_opcode_defs = { git = "https://github.com/matter-labs/era-zkevm_opcode_defs", branch = "v1.4.1" } zkevm_opcode_defs = { git = "https://github.com/matter-labs/era-zkevm_opcode_defs", branch = "v1.4.1" }
revive-common = { path = "../common" } revive-common = { path = "../common" }
@@ -33,4 +38,3 @@ pallet-contracts-pvm-llapi = { path = "../pallet-contracts-pvm-llapi" }
revive-linker = { path = "../linker" } revive-linker = { path = "../linker" }
revive-builtins = { path = "../builtins" } revive-builtins = { path = "../builtins" }
revive-stdlib = { path = "../stdlib" } revive-stdlib = { path = "../stdlib" }
revive-extensions = { path = "../extensions" }
@@ -1,10 +1,6 @@
//!
//! The debug IR type. //! The debug IR type.
//!
///
/// The debug IR type. /// The debug IR type.
///
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -24,9 +20,7 @@ pub enum IRType {
} }
impl IRType { impl IRType {
///
/// Returns the file extension for the specified IR. /// Returns the file extension for the specified IR.
///
pub fn file_extension(&self) -> &'static str { pub fn file_extension(&self) -> &'static str {
match self { match self {
Self::Yul => revive_common::EXTENSION_YUL, Self::Yul => revive_common::EXTENSION_YUL,
@@ -34,7 +28,7 @@ impl IRType {
Self::EVMLA => revive_common::EXTENSION_EVMLA, Self::EVMLA => revive_common::EXTENSION_EVMLA,
Self::LLL => revive_common::EXTENSION_LLL, Self::LLL => revive_common::EXTENSION_LLL,
Self::LLVM => revive_common::EXTENSION_LLVM_SOURCE, Self::LLVM => revive_common::EXTENSION_LLVM_SOURCE,
Self::Assembly => revive_common::EXTENSION_ERAVM_ASSEMBLY, Self::Assembly => revive_common::EXTENSION_POLKAVM_ASSEMBLY,
} }
} }
} }
@@ -1,6 +1,4 @@
//!
//! The debug configuration. //! The debug configuration.
//!
pub mod ir_type; pub mod ir_type;
@@ -11,9 +9,7 @@ use serde::Serialize;
use self::ir_type::IRType; use self::ir_type::IRType;
///
/// The debug configuration. /// The debug configuration.
///
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct DebugConfig { pub struct DebugConfig {
/// The directory to dump the IRs to. /// The directory to dump the IRs to.
@@ -21,16 +17,12 @@ pub struct DebugConfig {
} }
impl DebugConfig { impl DebugConfig {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(output_directory: PathBuf) -> Self { pub fn new(output_directory: PathBuf) -> Self {
Self { output_directory } Self { output_directory }
} }
///
/// Dumps the Yul IR. /// Dumps the Yul IR.
///
pub fn dump_yul(&self, contract_path: &str, code: &str) -> anyhow::Result<()> { pub fn dump_yul(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned(); let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul); let full_file_name = Self::full_file_name(contract_path, None, IRType::Yul);
@@ -40,9 +32,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Dumps the EVM legacy assembly IR. /// Dumps the EVM legacy assembly IR.
///
pub fn dump_evmla(&self, contract_path: &str, code: &str) -> anyhow::Result<()> { pub fn dump_evmla(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned(); let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EVMLA); let full_file_name = Self::full_file_name(contract_path, None, IRType::EVMLA);
@@ -52,9 +42,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Dumps the Ethereal IR. /// Dumps the Ethereal IR.
///
pub fn dump_ethir(&self, contract_path: &str, code: &str) -> anyhow::Result<()> { pub fn dump_ethir(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned(); let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::EthIR); let full_file_name = Self::full_file_name(contract_path, None, IRType::EthIR);
@@ -64,9 +52,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Dumps the LLL IR. /// Dumps the LLL IR.
///
pub fn dump_lll(&self, contract_path: &str, code: &str) -> anyhow::Result<()> { pub fn dump_lll(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned(); let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::LLL); let full_file_name = Self::full_file_name(contract_path, None, IRType::LLL);
@@ -76,9 +62,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Dumps the unoptimized LLVM IR. /// Dumps the unoptimized LLVM IR.
///
pub fn dump_llvm_ir_unoptimized( pub fn dump_llvm_ir_unoptimized(
&self, &self,
contract_path: &str, contract_path: &str,
@@ -94,9 +78,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Dumps the optimized LLVM IR. /// Dumps the optimized LLVM IR.
///
pub fn dump_llvm_ir_optimized( pub fn dump_llvm_ir_optimized(
&self, &self,
contract_path: &str, contract_path: &str,
@@ -112,9 +94,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Dumps the assembly. /// Dumps the assembly.
///
pub fn dump_assembly(&self, contract_path: &str, code: &str) -> anyhow::Result<()> { pub fn dump_assembly(&self, contract_path: &str, code: &str) -> anyhow::Result<()> {
let mut file_path = self.output_directory.to_owned(); let mut file_path = self.output_directory.to_owned();
let full_file_name = Self::full_file_name(contract_path, None, IRType::Assembly); let full_file_name = Self::full_file_name(contract_path, None, IRType::Assembly);
@@ -124,9 +104,7 @@ impl DebugConfig {
Ok(()) Ok(())
} }
///
/// Creates a full file name, given the contract full path, suffix, and extension. /// Creates a full file name, given the contract full path, suffix, and extension.
///
fn full_file_name(contract_path: &str, suffix: Option<&str>, ir_type: IRType) -> String { fn full_file_name(contract_path: &str, suffix: Option<&str>, ir_type: IRType) -> String {
let mut full_file_name = contract_path.replace('/', "_").replace(':', "."); let mut full_file_name = contract_path.replace('/', "_").replace(':', ".");
if let Some(suffix) = suffix { if let Some(suffix) = suffix {
@@ -1,149 +0,0 @@
//!
//! Translates the arithmetic operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the arithmetic addition.
///
pub fn addition<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_add(operand_1, operand_2, "addition_result")?
.as_basic_value_enum())
}
///
/// Translates the arithmetic subtraction.
///
pub fn subtraction<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_sub(operand_1, operand_2, "subtraction_result")?
.as_basic_value_enum())
}
///
/// Translates the arithmetic multiplication.
///
pub fn multiplication<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_mul(operand_1, operand_2, "multiplication_result")?
.as_basic_value_enum())
}
///
/// Translates the arithmetic division.
///
pub fn division<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_unsigned_div(operand_1, operand_2, "udiv")?
.into())
}
///
/// Translates the arithmetic remainder.
///
pub fn remainder<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.build_call(
context.llvm_runtime().r#mod,
&[
operand_1.as_basic_value_enum(),
operand_2.as_basic_value_enum(),
],
"add_mod_call",
)
.expect("Always exists"))
}
///
/// Translates the signed arithmetic division.
///
/// Two differences between the EVM and LLVM IR:
/// 1. In case of division by zero, 0 is returned.
/// 2. In case of overflow, the first argument is returned.
///
pub fn division_signed<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.build_call(
context.llvm_runtime().sdiv,
&[
operand_1.as_basic_value_enum(),
operand_2.as_basic_value_enum(),
],
"add_mod_call",
)
.expect("Always exists"))
}
///
/// Translates the signed arithmetic remainder.
///
pub fn remainder_signed<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.build_call(
context.llvm_runtime().smod,
&[
operand_1.as_basic_value_enum(),
operand_2.as_basic_value_enum(),
],
"add_mod_call",
)
.expect("Always exists"))
}
@@ -1,158 +0,0 @@
//!
//! Translates the context getter instructions.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `gas_limit` instruction.
///
pub fn gas_limit<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `gas_price` instruction.
///
pub fn gas_price<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `tx.origin` instruction.
///
pub fn origin<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `chain_id` instruction.
///
pub fn chain_id<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `block_number` instruction.
///
pub fn block_number<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `block_timestamp` instruction.
///
pub fn block_timestamp<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `block_hash` instruction.
///
pub fn block_hash<'ctx, D>(
_context: &mut Context<'ctx, D>,
_index: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `difficulty` instruction.
///
pub fn difficulty<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `coinbase` instruction.
///
pub fn coinbase<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `basefee` instruction.
///
pub fn basefee<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
///
/// Translates the `msize` instruction.
///
pub fn msize<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let heap_end = context.build_sbrk(context.xlen_type().const_zero())?;
let heap_start = context
.get_global(crate::eravm::GLOBAL_HEAP_MEMORY_POINTER)?
.value
.as_pointer_value();
let heap_size = context.builder().build_int_nuw_sub(
context
.builder()
.build_ptr_to_int(heap_end, context.xlen_type(), "heap_end")?,
context
.builder()
.build_ptr_to_int(heap_start, context.xlen_type(), "heap_start")?,
"heap_size",
)?;
Ok(context
.builder()
.build_int_z_extend(heap_size, context.field_type(), "heap_size_extended")?
.as_basic_value_enum())
}
@@ -1,51 +0,0 @@
//!
//! Translates the cryptographic operations.
//!
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `sha3` instruction.
///
pub fn sha3<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
length: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let offset_casted = context.safe_truncate_int_to_i32(offset)?;
let length_casted = context.safe_truncate_int_to_i32(length)?;
let input_pointer = context.build_heap_gep(offset_casted, length_casted)?;
let input_pointer_casted = context.builder().build_ptr_to_int(
input_pointer.value,
context.xlen_type(),
"input_pointer_casted",
)?;
let output_pointer = context.build_alloca(context.field_type(), "output_pointer");
let output_pointer_casted = context.builder().build_ptr_to_int(
output_pointer.value,
context.xlen_type(),
"output_pointer_casted",
)?;
let function = context
.module()
.get_function("hash_keccak_256")
.expect("is declared");
context.builder().build_call(
function,
&[
input_pointer_casted.into(),
length_casted.into(),
output_pointer_casted.into(),
],
"call_seal_hash_keccak_256",
)?;
context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?)
}
@@ -1,81 +0,0 @@
//!
//! Translates the value and balance operations.
//!
use inkwell::values::BasicValue;
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates the `gas` instruction.
///
pub fn gas<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context.integer_const(256, 0).as_basic_value_enum())
}
///
/// Translates the `value` instruction.
///
pub fn value<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let output_pointer = context.build_alloca(context.value_type(), "output_pointer");
let output_pointer_casted = context.builder().build_ptr_to_int(
output_pointer.value,
context.xlen_type(),
"output_pointer_casted",
)?;
let output_length_pointer = context.build_alloca(context.xlen_type(), "output_len_pointer");
let output_length_pointer_casted = context.builder().build_ptr_to_int(
output_length_pointer.value,
context.xlen_type(),
"output_pointer_casted",
)?;
context.build_store(
output_length_pointer,
context.integer_const(crate::eravm::XLEN, revive_common::BYTE_LENGTH_VALUE as u64),
)?;
context.builder().build_call(
context
.module()
.get_function("value_transferred")
.expect("is declared"),
&[
output_pointer_casted.into(),
output_length_pointer_casted.into(),
],
"call_seal_value_transferred",
)?;
let value = context.build_load(output_pointer, "transferred_value")?;
let value_extended = context.builder().build_int_z_extend(
value.into_int_value(),
context.field_type(),
"transferred_value_extended",
)?;
Ok(value_extended.as_basic_value_enum())
}
///
/// Translates the `balance` instructions.
///
pub fn balance<'ctx, D>(
_context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
@@ -1,78 +0,0 @@
//!
//! Translates a log or event call.
//!
use crate::eravm::context::Context;
use crate::eravm::Dependency;
///
/// Translates a log or event call.
///
/// The decoding logic is implemented in a system contract, which is called from here.
///
/// There are several cases of the translation for the sake of efficiency, since the front-end
/// emits topics and values sequentially by one, but the LLVM intrinsic and bytecode instruction
/// accept two at once.
///
pub fn log<'ctx, D>(
_context: &mut Context<'ctx, D>,
_input_offset: inkwell::values::IntValue<'ctx>,
_input_length: inkwell::values::IntValue<'ctx>,
_topics: Vec<inkwell::values::IntValue<'ctx>>,
) -> anyhow::Result<()>
where
D: Dependency + Clone,
{
/*
let failure_block = context.append_basic_block("event_failure_block");
let join_block = context.append_basic_block("event_join_block");
let gas = crate::eravm::evm::ether_gas::gas(context)?.into_int_value();
let abi_data = crate::eravm::utils::abi_data(
context,
input_offset,
input_length,
Some(gas),
AddressSpace::Heap,
true,
)?;
let mut extra_abi_data = Vec::with_capacity(1 + topics.len());
extra_abi_data.push(context.field_const(topics.len() as u64));
extra_abi_data.extend(topics);
let result = context
.build_call(
context.llvm_runtime().far_call,
crate::eravm::utils::external_call_arguments(
context,
abi_data.as_basic_value_enum(),
context.field_const(zkevm_opcode_defs::ADDRESS_EVENT_WRITER as u64),
extra_abi_data,
None,
)
.as_slice(),
"event_writer_call_external",
)
.expect("Always returns a value");
let result_status_code_boolean = context
.builder()
.build_extract_value(
result.into_struct_value(),
1,
"event_writer_external_result_status_code_boolean",
)
.expect("Always exists");
context.build_conditional_branch(
result_status_code_boolean.into_int_value(),
join_block,
failure_block,
)?;
context.set_basic_block(failure_block);
crate::eravm::evm::r#return::revert(context, context.field_const(0), context.field_const(0))?;
context.set_basic_block(join_block);
*/
Ok(())
}
+55 -59
View File
@@ -1,78 +1,74 @@
//!
//! The LLVM context library. //! The LLVM context library.
//!
pub(crate) mod debug_config; pub(crate) mod debug_config;
pub(crate) mod eravm;
pub(crate) mod optimizer; pub(crate) mod optimizer;
pub(crate) mod polkavm;
pub(crate) mod target_machine; pub(crate) mod target_machine;
pub use self::debug_config::ir_type::IRType as DebugConfigIR; pub use self::debug_config::ir_type::IRType as DebugConfigIR;
pub use self::debug_config::DebugConfig; pub use self::debug_config::DebugConfig;
pub use self::eravm::build_assembly_text as eravm_build_assembly_text;
pub use self::eravm::context::address_space::AddressSpace as EraVMAddressSpace;
pub use self::eravm::context::argument::Argument as EraVMArgument;
pub use self::eravm::context::attribute::Attribute as EraVMAttribute;
pub use self::eravm::context::build::Build as EraVMBuild;
pub use self::eravm::context::code_type::CodeType as EraVMCodeType;
pub use self::eravm::context::evmla_data::EVMLAData as EraVMContextEVMLAData;
pub use self::eravm::context::function::block::evmla_data::key::Key as EraVMFunctionBlockKey;
pub use self::eravm::context::function::block::evmla_data::EVMLAData as EraVMFunctionBlockEVMLAData;
pub use self::eravm::context::function::block::Block as EraVMFunctionBlock;
pub use self::eravm::context::function::declaration::Declaration as EraVMFunctionDeclaration;
pub use self::eravm::context::function::evmla_data::EVMLAData as EraVMFunctionEVMLAData;
pub use self::eravm::context::function::intrinsics::Intrinsics as EraVMIntrinsicFunction;
pub use self::eravm::context::function::llvm_runtime::LLVMRuntime as EraVMLLVMRuntime;
pub use self::eravm::context::function::r#return::Return as EraVMFunctionReturn;
pub use self::eravm::context::function::runtime::deploy_code::DeployCode as EraVMDeployCodeFunction;
pub use self::eravm::context::function::runtime::entry::Entry as EraVMEntryFunction;
pub use self::eravm::context::function::runtime::runtime_code::RuntimeCode as EraVMRuntimeCodeFunction;
pub use self::eravm::context::function::runtime::Runtime as EraVMRuntime;
pub use self::eravm::context::function::vyper_data::VyperData as EraVMFunctionVyperData;
pub use self::eravm::context::function::yul_data::YulData as EraVMFunctionYulData;
pub use self::eravm::context::function::Function as EraVMFunction;
pub use self::eravm::context::global::Global as EraVMGlobal;
pub use self::eravm::context::pointer::Pointer as EraVMPointer;
pub use self::eravm::context::r#loop::Loop as EraVMLoop;
pub use self::eravm::context::solidity_data::SolidityData as EraVMContextSolidityData;
pub use self::eravm::context::vyper_data::VyperData as EraVMContextVyperData;
pub use self::eravm::context::yul_data::YulData as EraVMContextYulData;
pub use self::eravm::context::Context as EraVMContext;
pub use self::eravm::evm::arithmetic as eravm_evm_arithmetic;
pub use self::eravm::evm::bitwise as eravm_evm_bitwise;
pub use self::eravm::evm::call as eravm_evm_call;
pub use self::eravm::evm::calldata as eravm_evm_calldata;
pub use self::eravm::evm::comparison as eravm_evm_comparison;
pub use self::eravm::evm::context as eravm_evm_contract_context;
pub use self::eravm::evm::create as eravm_evm_create;
pub use self::eravm::evm::crypto as eravm_evm_crypto;
pub use self::eravm::evm::ether_gas as eravm_evm_ether_gas;
pub use self::eravm::evm::event as eravm_evm_event;
pub use self::eravm::evm::ext_code as eravm_evm_ext_code;
pub use self::eravm::evm::immutable as eravm_evm_immutable;
pub use self::eravm::evm::math as eravm_evm_math;
pub use self::eravm::evm::memory as eravm_evm_memory;
pub use self::eravm::evm::r#return as eravm_evm_return;
pub use self::eravm::evm::return_data as eravm_evm_return_data;
pub use self::eravm::evm::storage as eravm_evm_storage;
pub use self::eravm::metadata_hash::MetadataHash as EraVMMetadataHash;
pub use self::eravm::r#const as eravm_const;
pub use self::eravm::utils as eravm_utils;
pub use self::eravm::Dependency as EraVMDependency;
pub use self::eravm::DummyDependency as EraVMDummyDependency;
pub use self::eravm::DummyLLVMWritable as EraVMDummyLLVMWritable;
pub use self::eravm::WriteLLVM as EraVMWriteLLVM;
pub use self::optimizer::settings::size_level::SizeLevel as OptimizerSettingsSizeLevel; pub use self::optimizer::settings::size_level::SizeLevel as OptimizerSettingsSizeLevel;
pub use self::optimizer::settings::Settings as OptimizerSettings; pub use self::optimizer::settings::Settings as OptimizerSettings;
pub use self::optimizer::Optimizer; pub use self::optimizer::Optimizer;
pub use self::polkavm::build_assembly_text as polkavm_build_assembly_text;
pub use self::polkavm::context::address_space::AddressSpace as PolkaVMAddressSpace;
pub use self::polkavm::context::argument::Argument as PolkaVMArgument;
pub use self::polkavm::context::attribute::Attribute as PolkaVMAttribute;
pub use self::polkavm::context::build::Build as PolkaVMBuild;
pub use self::polkavm::context::code_type::CodeType as PolkaVMCodeType;
pub use self::polkavm::context::evmla_data::EVMLAData as PolkaVMContextEVMLAData;
pub use self::polkavm::context::function::block::evmla_data::key::Key as PolkaVMFunctionBlockKey;
pub use self::polkavm::context::function::block::evmla_data::EVMLAData as PolkaVMFunctionBlockEVMLAData;
pub use self::polkavm::context::function::block::Block as PolkaVMFunctionBlock;
pub use self::polkavm::context::function::declaration::Declaration as PolkaVMFunctionDeclaration;
pub use self::polkavm::context::function::evmla_data::EVMLAData as PolkaVMFunctionEVMLAData;
pub use self::polkavm::context::function::intrinsics::Intrinsics as PolkaVMIntrinsicFunction;
pub use self::polkavm::context::function::llvm_runtime::LLVMRuntime as PolkaVMLLVMRuntime;
pub use self::polkavm::context::function::r#return::Return as PolkaVMFunctionReturn;
pub use self::polkavm::context::function::runtime::deploy_code::DeployCode as PolkaVMDeployCodeFunction;
pub use self::polkavm::context::function::runtime::entry::Entry as PolkaVMEntryFunction;
pub use self::polkavm::context::function::runtime::runtime_code::RuntimeCode as PolkaVMRuntimeCodeFunction;
pub use self::polkavm::context::function::runtime::Runtime as PolkaVMRuntime;
pub use self::polkavm::context::function::vyper_data::VyperData as PolkaVMFunctionVyperData;
pub use self::polkavm::context::function::yul_data::YulData as PolkaVMFunctionYulData;
pub use self::polkavm::context::function::Function as PolkaVMFunction;
pub use self::polkavm::context::global::Global as PolkaVMGlobal;
pub use self::polkavm::context::pointer::Pointer as PolkaVMPointer;
pub use self::polkavm::context::r#loop::Loop as PolkaVMLoop;
pub use self::polkavm::context::solidity_data::SolidityData as PolkaVMContextSolidityData;
pub use self::polkavm::context::vyper_data::VyperData as PolkaVMContextVyperData;
pub use self::polkavm::context::yul_data::YulData as PolkaVMContextYulData;
pub use self::polkavm::context::Context as PolkaVMContext;
pub use self::polkavm::evm::arithmetic as polkavm_evm_arithmetic;
pub use self::polkavm::evm::bitwise as polkavm_evm_bitwise;
pub use self::polkavm::evm::call as polkavm_evm_call;
pub use self::polkavm::evm::calldata as polkavm_evm_calldata;
pub use self::polkavm::evm::comparison as polkavm_evm_comparison;
pub use self::polkavm::evm::context as polkavm_evm_contract_context;
pub use self::polkavm::evm::create as polkavm_evm_create;
pub use self::polkavm::evm::crypto as polkavm_evm_crypto;
pub use self::polkavm::evm::ether_gas as polkavm_evm_ether_gas;
pub use self::polkavm::evm::event as polkavm_evm_event;
pub use self::polkavm::evm::ext_code as polkavm_evm_ext_code;
pub use self::polkavm::evm::immutable as polkavm_evm_immutable;
pub use self::polkavm::evm::math as polkavm_evm_math;
pub use self::polkavm::evm::memory as polkavm_evm_memory;
pub use self::polkavm::evm::r#return as polkavm_evm_return;
pub use self::polkavm::evm::return_data as polkavm_evm_return_data;
pub use self::polkavm::evm::storage as polkavm_evm_storage;
pub use self::polkavm::metadata_hash::MetadataHash as PolkaVMMetadataHash;
pub use self::polkavm::r#const as polkavm_const;
pub use self::polkavm::utils as polkavm_utils;
pub use self::polkavm::Dependency as PolkaVMDependency;
pub use self::polkavm::DummyDependency as PolkaVMDummyDependency;
pub use self::polkavm::DummyLLVMWritable as PolkaVMDummyLLVMWritable;
pub use self::polkavm::WriteLLVM as PolkaVMWriteLLVM;
pub use self::target_machine::target::Target; pub use self::target_machine::target::Target;
pub use self::target_machine::TargetMachine; pub use self::target_machine::TargetMachine;
///
/// Initializes the target machine. /// Initializes the target machine.
///
pub fn initialize_target(target: Target) { pub fn initialize_target(target: Target) {
match target { match target {
Target::PVM => self::eravm::initialize_target(), Target::PVM => self::polkavm::initialize_target(),
} }
} }
-10
View File
@@ -1,6 +1,4 @@
//!
//! The LLVM optimizing tools. //! The LLVM optimizing tools.
//!
pub mod settings; pub mod settings;
@@ -11,9 +9,7 @@ use crate::target_machine::TargetMachine;
use self::settings::Settings; use self::settings::Settings;
///
/// The LLVM optimizing tools. /// The LLVM optimizing tools.
///
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Optimizer { pub struct Optimizer {
/// The optimizer settings. /// The optimizer settings.
@@ -21,16 +17,12 @@ pub struct Optimizer {
} }
impl Optimizer { impl Optimizer {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(settings: Settings) -> Self { pub fn new(settings: Settings) -> Self {
Self { settings } Self { settings }
} }
///
/// Runs the new pass manager. /// Runs the new pass manager.
///
pub fn run( pub fn run(
&self, &self,
target_machine: &TargetMachine, target_machine: &TargetMachine,
@@ -42,9 +34,7 @@ impl Optimizer {
) )
} }
///
/// Returns the optimizer settings reference. /// Returns the optimizer settings reference.
///
pub fn settings(&self) -> &Settings { pub fn settings(&self) -> &Settings {
&self.settings &self.settings
} }
@@ -1,6 +1,4 @@
//!
//! The LLVM optimizer settings. //! The LLVM optimizer settings.
//!
pub mod size_level; pub mod size_level;
@@ -11,9 +9,7 @@ use itertools::Itertools;
use self::size_level::SizeLevel; use self::size_level::SizeLevel;
///
/// The LLVM optimizer settings. /// The LLVM optimizer settings.
///
#[derive(Debug, Serialize, Deserialize, Clone, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, Eq)]
pub struct Settings { pub struct Settings {
/// The middle-end optimization level. /// The middle-end optimization level.
@@ -35,9 +31,7 @@ pub struct Settings {
} }
impl Settings { impl Settings {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
level_middle_end: inkwell::OptimizationLevel, level_middle_end: inkwell::OptimizationLevel,
level_middle_end_size: SizeLevel, level_middle_end_size: SizeLevel,
@@ -56,9 +50,7 @@ impl Settings {
} }
} }
///
/// A shortcut constructor with debugging tools. /// A shortcut constructor with debugging tools.
///
pub fn new_debug( pub fn new_debug(
level_middle_end: inkwell::OptimizationLevel, level_middle_end: inkwell::OptimizationLevel,
level_middle_end_size: SizeLevel, level_middle_end_size: SizeLevel,
@@ -80,9 +72,7 @@ impl Settings {
} }
} }
///
/// Creates settings from a CLI optimization parameter. /// Creates settings from a CLI optimization parameter.
///
pub fn try_from_cli(value: char) -> anyhow::Result<Self> { pub fn try_from_cli(value: char) -> anyhow::Result<Self> {
Ok(match value { Ok(match value {
'0' => Self::new( '0' => Self::new(
@@ -126,9 +116,7 @@ impl Settings {
}) })
} }
///
/// Returns the settings without optimizations. /// Returns the settings without optimizations.
///
pub fn none() -> Self { pub fn none() -> Self {
Self::new( Self::new(
inkwell::OptimizationLevel::None, inkwell::OptimizationLevel::None,
@@ -137,9 +125,7 @@ impl Settings {
) )
} }
///
/// Returns the settings for the optimal number of VM execution cycles. /// Returns the settings for the optimal number of VM execution cycles.
///
pub fn cycles() -> Self { pub fn cycles() -> Self {
Self::new( Self::new(
inkwell::OptimizationLevel::Aggressive, inkwell::OptimizationLevel::Aggressive,
@@ -148,9 +134,7 @@ impl Settings {
) )
} }
///
/// Returns the settings for the optimal size. /// Returns the settings for the optimal size.
///
pub fn size() -> Self { pub fn size() -> Self {
Self::new( Self::new(
inkwell::OptimizationLevel::Default, inkwell::OptimizationLevel::Default,
@@ -159,9 +143,7 @@ impl Settings {
) )
} }
///
/// Returns the middle-end optimization parameter as string. /// Returns the middle-end optimization parameter as string.
///
pub fn middle_end_as_string(&self) -> String { pub fn middle_end_as_string(&self) -> String {
match self.level_middle_end_size { match self.level_middle_end_size {
SizeLevel::Zero => (self.level_middle_end as u8).to_string(), SizeLevel::Zero => (self.level_middle_end as u8).to_string(),
@@ -169,19 +151,14 @@ impl Settings {
} }
} }
///
/// Checks whether there are middle-end optimizations enabled. /// Checks whether there are middle-end optimizations enabled.
///
pub fn is_middle_end_enabled(&self) -> bool { pub fn is_middle_end_enabled(&self) -> bool {
self.level_middle_end != inkwell::OptimizationLevel::None self.level_middle_end != inkwell::OptimizationLevel::None
|| self.level_middle_end_size != SizeLevel::Zero || self.level_middle_end_size != SizeLevel::Zero
} }
///
/// Returns all possible combinations of the optimizer settings. /// Returns all possible combinations of the optimizer settings.
///
/// Used only for testing purposes. /// Used only for testing purposes.
///
pub fn combinations() -> Vec<Self> { pub fn combinations() -> Vec<Self> {
let performance_combinations: Vec<Self> = vec![ let performance_combinations: Vec<Self> = vec![
inkwell::OptimizationLevel::None, inkwell::OptimizationLevel::None,
@@ -224,30 +201,22 @@ impl Settings {
combinations combinations
} }
///
/// Sets the fallback to optimizing for size if the bytecode is too large. /// Sets the fallback to optimizing for size if the bytecode is too large.
///
pub fn enable_fallback_to_size(&mut self) { pub fn enable_fallback_to_size(&mut self) {
self.is_fallback_to_size_enabled = true; self.is_fallback_to_size_enabled = true;
} }
///
/// Disables the system request memoization. /// Disables the system request memoization.
///
pub fn disable_system_request_memoization(&mut self) { pub fn disable_system_request_memoization(&mut self) {
self.is_system_request_memoization_disabled = true; self.is_system_request_memoization_disabled = true;
} }
///
/// Whether the fallback to optimizing for size is enabled. /// Whether the fallback to optimizing for size is enabled.
///
pub fn is_fallback_to_size_enabled(&self) -> bool { pub fn is_fallback_to_size_enabled(&self) -> bool {
self.is_fallback_to_size_enabled self.is_fallback_to_size_enabled
} }
///
/// Whether the system request memoization is disabled. /// Whether the system request memoization is disabled.
///
pub fn is_system_request_memoization_disabled(&self) -> bool { pub fn is_system_request_memoization_disabled(&self) -> bool {
self.is_system_request_memoization_disabled self.is_system_request_memoization_disabled
} }
@@ -1,13 +1,9 @@
//!
//! The LLVM optimizer settings size level. //! The LLVM optimizer settings size level.
//!
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
///
/// The LLVM optimizer settings size level. /// The LLVM optimizer settings size level.
///
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
pub enum SizeLevel { pub enum SizeLevel {
/// No size optimizations. /// No size optimizations.
@@ -1,11 +1,12 @@
//!
//! The LLVM context constants. //! The LLVM context constants.
//!
/// Runtime API methods.
pub mod runtime_api;
/// The LLVM framework version. /// The LLVM framework version.
pub const LLVM_VERSION: semver::Version = semver::Version::new(18, 1, 4); pub const LLVM_VERSION: semver::Version = semver::Version::new(18, 1, 4);
/// The EraVM version. /// The PolkaVM version.
pub const ZKEVM_VERSION: semver::Version = semver::Version::new(1, 3, 2); pub const ZKEVM_VERSION: semver::Version = semver::Version::new(1, 3, 2);
/// The register width sized type /// The register width sized type
@@ -41,12 +42,21 @@ pub static GLOBAL_CONST_ARRAY_PREFIX: &str = "const_array_";
/// The global verbatim getter identifier prefix. /// The global verbatim getter identifier prefix.
pub static GLOBAL_VERBATIM_GETTER_PREFIX: &str = "get_global::"; pub static GLOBAL_VERBATIM_GETTER_PREFIX: &str = "get_global::";
/// The static word size.
pub static GLOBAL_I256_SIZE: &str = "i256_size";
/// The static value size.
pub static GLOBAL_I160_SIZE: &str = "i160_size";
/// The static i64 size.
pub static GLOBAL_I64_SIZE: &str = "i64_size";
/// The external call data offset in the auxiliary heap. /// The external call data offset in the auxiliary heap.
pub const HEAP_AUX_OFFSET_EXTERNAL_CALL: u64 = 0; pub const HEAP_AUX_OFFSET_EXTERNAL_CALL: u64 = 0;
/// The constructor return data offset in the auxiliary heap. /// The constructor return data offset in the auxiliary heap.
pub const HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA: u64 = pub const HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA: u64 =
8 * (revive_common::BYTE_LENGTH_FIELD as u64); 8 * (revive_common::BYTE_LENGTH_WORD as u64);
/// The number of the extra ABI data arguments. /// The number of the extra ABI data arguments.
pub const EXTRA_ABI_DATA_SIZE: usize = 0; pub const EXTRA_ABI_DATA_SIZE: usize = 0;
@@ -63,13 +73,11 @@ pub const NO_SYSTEM_CALL_BIT: bool = false;
/// The system call bit. /// The system call bit.
pub const SYSTEM_CALL_BIT: bool = true; pub const SYSTEM_CALL_BIT: bool = true;
///
/// The deployer call header size that consists of: /// The deployer call header size that consists of:
/// - selector (4 bytes) /// - selector (4 bytes)
/// - salt (32 bytes) /// - salt (32 bytes)
/// - bytecode hash (32 bytes) /// - bytecode hash (32 bytes)
/// - constructor arguments offset (32 bytes) /// - constructor arguments offset (32 bytes)
/// - constructor arguments length (32 bytes) /// - constructor arguments length (32 bytes)
///
pub const DEPLOYER_CALL_HEADER_SIZE: usize = pub const DEPLOYER_CALL_HEADER_SIZE: usize =
revive_common::BYTE_LENGTH_X32 + (revive_common::BYTE_LENGTH_FIELD * 4); revive_common::BYTE_LENGTH_X32 + (revive_common::BYTE_LENGTH_WORD * 4);
@@ -0,0 +1,52 @@
//! Runtime API import and export symbols.
/// The contract deploy export.
pub static CALL: &str = "call";
/// The contract call export.
pub static DEPLOY: &str = "deploy";
/// All exported symbols.
/// Useful for configuring common attributes and linkage.
pub static EXPORTS: [&str; 2] = [CALL, DEPLOY];
pub static ADDRESS: &str = "address";
pub static BLOCK_NUMBER: &str = "block_number";
pub static CALLER: &str = "caller";
pub static DEPOSIT_EVENT: &str = "deposit_event";
pub static GET_STORAGE: &str = "get_storage";
pub static HASH_KECCAK_256: &str = "hash_keccak_256";
pub static INPUT: &str = "input";
pub static NOW: &str = "now";
pub static RETURN: &str = "seal_return";
pub static SET_STORAGE: &str = "set_storage";
pub static VALUE_TRANSFERRED: &str = "value_transferred";
/// All imported runtime API symbols..
/// Useful for configuring common attributes and linkage.
pub static IMPORTS: [&str; 11] = [
ADDRESS,
BLOCK_NUMBER,
CALLER,
DEPOSIT_EVENT,
GET_STORAGE,
HASH_KECCAK_256,
INPUT,
NOW,
RETURN,
SET_STORAGE,
VALUE_TRANSFERRED,
];
/// PolkaVM __sbrk API symbol to extend the heap memory.
pub static SBRK: &str = "__sbrk";
@@ -1,10 +1,6 @@
//!
//! The address space aliases. //! The address space aliases.
//!
///
/// The address space aliases. /// The address space aliases.
///
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AddressSpace { pub enum AddressSpace {
/// The stack memory. /// The stack memory.
@@ -1,10 +1,6 @@
//!
//! The LLVM argument with metadata. //! The LLVM argument with metadata.
//!
///
/// The LLVM argument with metadata. /// The LLVM argument with metadata.
///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Argument<'ctx> { pub struct Argument<'ctx> {
/// The actual LLVM operand. /// The actual LLVM operand.
@@ -22,9 +18,7 @@ impl<'ctx> Argument<'ctx> {
/// The calldata length argument index. /// The calldata length argument index.
pub const ARGUMENT_INDEX_CALLDATA_LENGTH: usize = 1; pub const ARGUMENT_INDEX_CALLDATA_LENGTH: usize = 1;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(value: inkwell::values::BasicValueEnum<'ctx>) -> Self { pub fn new(value: inkwell::values::BasicValueEnum<'ctx>) -> Self {
Self { Self {
value, value,
@@ -33,9 +27,7 @@ impl<'ctx> Argument<'ctx> {
} }
} }
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new_with_original( pub fn new_with_original(
value: inkwell::values::BasicValueEnum<'ctx>, value: inkwell::values::BasicValueEnum<'ctx>,
original: String, original: String,
@@ -47,9 +39,7 @@ impl<'ctx> Argument<'ctx> {
} }
} }
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new_with_constant( pub fn new_with_constant(
value: inkwell::values::BasicValueEnum<'ctx>, value: inkwell::values::BasicValueEnum<'ctx>,
constant: num::BigUint, constant: num::BigUint,
@@ -61,9 +51,7 @@ impl<'ctx> Argument<'ctx> {
} }
} }
///
/// Returns the inner LLVM value. /// Returns the inner LLVM value.
///
pub fn to_llvm(&self) -> inkwell::values::BasicValueEnum<'ctx> { pub fn to_llvm(&self) -> inkwell::values::BasicValueEnum<'ctx> {
self.value self.value
} }
@@ -4,11 +4,8 @@ use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
/// The LLVM attribute. /// The LLVM attribute.
///
/// In order to check the real order in a new major version of LLVM, find the `Attributes.inc` file /// In order to check the real order in a new major version of LLVM, find the `Attributes.inc` file
/// inside of the LLVM build directory. This order is actually generated during the building. /// inside of the LLVM build directory. This order is actually generated during the building.
///
/// FIXME: Generate this in build.rs?
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Attribute { pub enum Attribute {
Unused = 0, Unused = 0,
@@ -84,7 +81,7 @@ pub enum Attribute {
Writable = 70, Writable = 70,
WriteOnly = 71, WriteOnly = 71,
ZExt = 72, ZExt = 72,
//LastEnumAttr = 72, // LastEnumAttr = 72,
// FirstTypeAttr = 73, // FirstTypeAttr = 73,
ByRef = 73, ByRef = 73,
ByVal = 74, ByVal = 74,
@@ -119,12 +116,7 @@ impl TryFrom<&str> for Attribute {
"OptimizeForSize" => Ok(Attribute::OptimizeForSize), "OptimizeForSize" => Ok(Attribute::OptimizeForSize),
"NoInline" => Ok(Attribute::NoInline), "NoInline" => Ok(Attribute::NoInline),
"WillReturn" => Ok(Attribute::WillReturn), "WillReturn" => Ok(Attribute::WillReturn),
"WriteOnly" => Ok(Attribute::WriteOnly),
"ReadNone" => Ok(Attribute::ReadNone),
"ReadOnly" => Ok(Attribute::ReadOnly),
"NoReturn" => Ok(Attribute::NoReturn), "NoReturn" => Ok(Attribute::NoReturn),
// FIXME: Not in Attributes.inc
//"InaccessibleMemOnly" => Ok(Attribute::InaccessibleMemOnly),
"MustProgress" => Ok(Attribute::MustProgress), "MustProgress" => Ok(Attribute::MustProgress),
_ => Err(value.to_owned()), _ => Err(value.to_owned()),
} }
@@ -1,36 +1,30 @@
//!
//! The LLVM module build. //! The LLVM module build.
//!
use std::collections::BTreeMap; use std::collections::BTreeMap;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
///
/// The LLVM module build. /// The LLVM module build.
///
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Build { pub struct Build {
/// The EraVM text assembly. /// The PolkaVM text assembly.
pub assembly_text: String, pub assembly_text: String,
/// The metadata hash. /// The metadata hash.
pub metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_FIELD]>, pub metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_WORD]>,
/// The EraVM binary bytecode. /// The PolkaVM binary bytecode.
pub bytecode: Vec<u8>, pub bytecode: Vec<u8>,
/// The EraVM bytecode hash. /// The PolkaVM bytecode hash.
pub bytecode_hash: String, pub bytecode_hash: String,
/// The hash-to-full-path mapping of the contract factory dependencies. /// The hash-to-full-path mapping of the contract factory dependencies.
pub factory_dependencies: BTreeMap<String, String>, pub factory_dependencies: BTreeMap<String, String>,
} }
impl Build { impl Build {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
assembly_text: String, assembly_text: String,
metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_FIELD]>, metadata_hash: Option<[u8; revive_common::BYTE_LENGTH_WORD]>,
bytecode: Vec<u8>, bytecode: Vec<u8>,
bytecode_hash: String, bytecode_hash: String,
) -> Self { ) -> Self {
@@ -1,13 +1,8 @@
//!
//! The contract code types. //! The contract code types.
//!
///
/// The contract code types (deploy and runtime). /// The contract code types (deploy and runtime).
///
/// They do not represent any entities in the final bytecode, but this separation is always present /// They do not represent any entities in the final bytecode, but this separation is always present
/// in the IRs used for translation to the EVM bytecode. /// in the IRs used for translation to the EVM bytecode.
///
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CodeType { pub enum CodeType {
/// The deploy code. /// The deploy code.
@@ -1,13 +1,9 @@
//!
//! The LLVM debug information. //! The LLVM debug information.
//!
use inkwell::debug_info::AsDIScope; use inkwell::debug_info::AsDIScope;
use num::Zero; use num::Zero;
///
/// The LLVM debug information. /// The LLVM debug information.
///
pub struct DebugInfo<'ctx> { pub struct DebugInfo<'ctx> {
/// The compile unit. /// The compile unit.
compile_unit: inkwell::debug_info::DICompileUnit<'ctx>, compile_unit: inkwell::debug_info::DICompileUnit<'ctx>,
@@ -16,9 +12,7 @@ pub struct DebugInfo<'ctx> {
} }
impl<'ctx> DebugInfo<'ctx> { impl<'ctx> DebugInfo<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(module: &inkwell::module::Module<'ctx>) -> Self { pub fn new(module: &inkwell::module::Module<'ctx>) -> Self {
let (builder, compile_unit) = module.create_debug_info_builder( let (builder, compile_unit) = module.create_debug_info_builder(
true, true,
@@ -44,16 +38,14 @@ impl<'ctx> DebugInfo<'ctx> {
} }
} }
///
/// Creates a function info. /// Creates a function info.
///
pub fn create_function( pub fn create_function(
&self, &self,
name: &str, name: &str,
) -> anyhow::Result<inkwell::debug_info::DISubprogram<'ctx>> { ) -> anyhow::Result<inkwell::debug_info::DISubprogram<'ctx>> {
let subroutine_type = self.builder.create_subroutine_type( let subroutine_type = self.builder.create_subroutine_type(
self.compile_unit.get_file(), self.compile_unit.get_file(),
Some(self.create_type(era_compiler_common::BIT_LENGTH_FIELD)?), Some(self.create_type(revive_common::BIT_LENGTH_FIELD)?),
&[], &[],
inkwell::debug_info::DIFlags::zero(), inkwell::debug_info::DIFlags::zero(),
); );
@@ -82,9 +74,7 @@ impl<'ctx> DebugInfo<'ctx> {
Ok(function) Ok(function)
} }
///
/// Creates a primitive type info. /// Creates a primitive type info.
///
pub fn create_type( pub fn create_type(
&self, &self,
bit_length: usize, bit_length: usize,
@@ -100,9 +90,7 @@ impl<'ctx> DebugInfo<'ctx> {
.map_err(|error| anyhow::anyhow!("Debug info error: {}", error)) .map_err(|error| anyhow::anyhow!("Debug info error: {}", error))
} }
///
/// Finalizes the builder. /// Finalizes the builder.
///
pub fn finalize(&self) { pub fn finalize(&self) {
self.builder.finalize(); self.builder.finalize();
} }
@@ -1,14 +1,9 @@
//!
//! The LLVM IR generator EVM legacy assembly data. //! The LLVM IR generator EVM legacy assembly data.
//!
use crate::eravm::context::argument::Argument; use crate::polkavm::context::argument::Argument;
///
/// The LLVM IR generator EVM legacy assembly data. /// The LLVM IR generator EVM legacy assembly data.
///
/// Describes some data that is only relevant to the EVM legacy assembly. /// Describes some data that is only relevant to the EVM legacy assembly.
///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EVMLAData<'ctx> { pub struct EVMLAData<'ctx> {
/// The Solidity compiler version. /// The Solidity compiler version.
@@ -22,9 +17,7 @@ impl<'ctx> EVMLAData<'ctx> {
/// The default stack size. /// The default stack size.
pub const DEFAULT_STACK_SIZE: usize = 64; pub const DEFAULT_STACK_SIZE: usize = 64;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(version: semver::Version) -> Self { pub fn new(version: semver::Version) -> Self {
Self { Self {
version, version,
@@ -1,14 +1,9 @@
//!
//! The LLVM IR generator function block key. //! The LLVM IR generator function block key.
//!
use crate::eravm::context::code_type::CodeType; use crate::polkavm::context::code_type::CodeType;
///
/// The LLVM IR generator function block key. /// The LLVM IR generator function block key.
///
/// Is only relevant to the EVM legacy assembly. /// Is only relevant to the EVM legacy assembly.
///
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Key { pub struct Key {
/// The block code type. /// The block code type.
@@ -18,9 +13,7 @@ pub struct Key {
} }
impl Key { impl Key {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(code_type: CodeType, tag: num::BigUint) -> Self { pub fn new(code_type: CodeType, tag: num::BigUint) -> Self {
Self { code_type, tag } Self { code_type, tag }
} }
@@ -1,14 +1,9 @@
//!
//! The LLVM function block EVM legacy assembly data. //! The LLVM function block EVM legacy assembly data.
//!
pub mod key; pub mod key;
///
/// The LLVM function block EVM legacy assembly data. /// The LLVM function block EVM legacy assembly data.
///
/// Describes some data that is only relevant to the EVM legacy assembly. /// Describes some data that is only relevant to the EVM legacy assembly.
///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EVMLAData { pub struct EVMLAData {
/// The initial hashes of the allowed stack states. /// The initial hashes of the allowed stack states.
@@ -16,9 +11,7 @@ pub struct EVMLAData {
} }
impl EVMLAData { impl EVMLAData {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(stack_hashes: Vec<md5::Digest>) -> Self { pub fn new(stack_hashes: Vec<md5::Digest>) -> Self {
Self { stack_hashes } Self { stack_hashes }
} }
@@ -1,14 +1,10 @@
//!
//! The LLVM IR generator function block. //! The LLVM IR generator function block.
//!
pub mod evmla_data; pub mod evmla_data;
use self::evmla_data::EVMLAData; use self::evmla_data::EVMLAData;
///
/// The LLVM IR generator function block. /// The LLVM IR generator function block.
///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Block<'ctx> { pub struct Block<'ctx> {
/// The inner block. /// The inner block.
@@ -18,9 +14,7 @@ pub struct Block<'ctx> {
} }
impl<'ctx> Block<'ctx> { impl<'ctx> Block<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(inner: inkwell::basic_block::BasicBlock<'ctx>) -> Self { pub fn new(inner: inkwell::basic_block::BasicBlock<'ctx>) -> Self {
Self { Self {
inner, inner,
@@ -28,38 +22,28 @@ impl<'ctx> Block<'ctx> {
} }
} }
///
/// Sets the EVM legacy assembly data. /// Sets the EVM legacy assembly data.
///
pub fn set_evmla_data(&mut self, data: EVMLAData) { pub fn set_evmla_data(&mut self, data: EVMLAData) {
self.evmla_data = Some(data); self.evmla_data = Some(data);
} }
///
/// The LLVM object reference. /// The LLVM object reference.
///
pub fn inner(&self) -> inkwell::basic_block::BasicBlock<'ctx> { pub fn inner(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.inner self.inner
} }
///
/// Returns the EVM data reference. /// Returns the EVM data reference.
///
/// # Panics /// # Panics
/// If the EVM data has not been initialized. /// If the EVM data has not been initialized.
///
pub fn evm(&self) -> &EVMLAData { pub fn evm(&self) -> &EVMLAData {
self.evmla_data self.evmla_data
.as_ref() .as_ref()
.expect("The EVM data must have been initialized") .expect("The EVM data must have been initialized")
} }
///
/// Returns the EVM data mutable reference. /// Returns the EVM data mutable reference.
///
/// # Panics /// # Panics
/// If the EVM data has not been initialized. /// If the EVM data has not been initialized.
///
pub fn evm_mut(&mut self) -> &mut EVMLAData { pub fn evm_mut(&mut self) -> &mut EVMLAData {
self.evmla_data self.evmla_data
.as_mut() .as_mut()
@@ -1,10 +1,6 @@
//!
//! The LLVM function declaration. //! The LLVM function declaration.
//!
///
/// The LLVM function declaration. /// The LLVM function declaration.
///
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Declaration<'ctx> { pub struct Declaration<'ctx> {
/// The function type. /// The function type.
@@ -14,9 +10,7 @@ pub struct Declaration<'ctx> {
} }
impl<'ctx> Declaration<'ctx> { impl<'ctx> Declaration<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
r#type: inkwell::types::FunctionType<'ctx>, r#type: inkwell::types::FunctionType<'ctx>,
value: inkwell::values::FunctionValue<'ctx>, value: inkwell::values::FunctionValue<'ctx>,
@@ -1,17 +1,12 @@
//!
//! The LLVM function EVM legacy assembly data. //! The LLVM function EVM legacy assembly data.
//!
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::eravm::context::function::block::evmla_data::key::Key as BlockKey; use crate::polkavm::context::function::block::evmla_data::key::Key as BlockKey;
use crate::eravm::context::function::block::Block; use crate::polkavm::context::function::block::Block;
///
/// The LLVM function EVM legacy assembly data. /// The LLVM function EVM legacy assembly data.
///
/// Describes some data that is only relevant to the EVM legacy assembly. /// Describes some data that is only relevant to the EVM legacy assembly.
///
#[derive(Debug)] #[derive(Debug)]
pub struct EVMLAData<'ctx> { pub struct EVMLAData<'ctx> {
/// The ordinary blocks with numeric tags. /// The ordinary blocks with numeric tags.
@@ -22,9 +17,7 @@ pub struct EVMLAData<'ctx> {
} }
impl<'ctx> EVMLAData<'ctx> { impl<'ctx> EVMLAData<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(stack_size: usize) -> Self { pub fn new(stack_size: usize) -> Self {
Self { Self {
blocks: BTreeMap::new(), blocks: BTreeMap::new(),
@@ -32,9 +25,7 @@ impl<'ctx> EVMLAData<'ctx> {
} }
} }
///
/// Inserts a function block. /// Inserts a function block.
///
pub fn insert_block(&mut self, key: BlockKey, block: Block<'ctx>) { pub fn insert_block(&mut self, key: BlockKey, block: Block<'ctx>) {
if let Some(blocks) = self.blocks.get_mut(&key) { if let Some(blocks) = self.blocks.get_mut(&key) {
blocks.push(block); blocks.push(block);
@@ -43,11 +34,8 @@ impl<'ctx> EVMLAData<'ctx> {
} }
} }
///
/// Returns the block with the specified tag and initial stack pattern. /// Returns the block with the specified tag and initial stack pattern.
///
/// If there is only one block, it is returned unconditionally. /// If there is only one block, it is returned unconditionally.
///
pub fn find_block( pub fn find_block(
&self, &self,
key: &BlockKey, key: &BlockKey,
@@ -1,17 +1,12 @@
//!
//! The LLVM intrinsic functions. //! The LLVM intrinsic functions.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::function::declaration::Declaration as FunctionDeclaration; use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
///
/// The LLVM intrinsic functions, implemented in the LLVM back-end. /// The LLVM intrinsic functions, implemented in the LLVM back-end.
///
/// Most of them are translated directly into bytecode instructions. /// Most of them are translated directly into bytecode instructions.
///
#[derive(Debug)] #[derive(Debug)]
pub struct Intrinsics<'ctx> { pub struct Intrinsics<'ctx> {
/// The trap. /// The trap.
@@ -21,7 +16,9 @@ pub struct Intrinsics<'ctx> {
/// The memory copy from a generic page. /// The memory copy from a generic page.
pub memory_copy_from_generic: FunctionDeclaration<'ctx>, pub memory_copy_from_generic: FunctionDeclaration<'ctx>,
/// Performs endianness swaps on i256 values /// Performs endianness swaps on i256 values
pub byte_swap: FunctionDeclaration<'ctx>, pub byte_swap_word: FunctionDeclaration<'ctx>,
/// Performs endianness swaps on i160 values
pub byte_swap_eth_address: FunctionDeclaration<'ctx>,
} }
impl<'ctx> Intrinsics<'ctx> { impl<'ctx> Intrinsics<'ctx> {
@@ -35,18 +32,20 @@ impl<'ctx> Intrinsics<'ctx> {
pub const FUNCTION_MEMORY_COPY_FROM_GENERIC: &'static str = "llvm.memcpy.p3.p1.i256"; pub const FUNCTION_MEMORY_COPY_FROM_GENERIC: &'static str = "llvm.memcpy.p3.p1.i256";
/// The corresponding intrinsic function name. /// The corresponding intrinsic function name.
pub const FUNCTION_BYTE_SWAP: &'static str = "llvm.bswap.i256"; pub const FUNCTION_BYTE_SWAP_WORD: &'static str = "llvm.bswap.i256";
/// The corresponding intrinsic function name.
pub const FUNCTION_BYTE_SWAP_ETH_ADDRESS: &'static str = "llvm.bswap.i160";
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>, module: &inkwell::module::Module<'ctx>,
) -> Self { ) -> Self {
let void_type = llvm.void_type(); let void_type = llvm.void_type();
let bool_type = llvm.bool_type(); let bool_type = llvm.bool_type();
let field_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32); let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32);
let address_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_ETH_ADDRESS as u32);
let _stack_field_pointer_type = llvm.ptr_type(AddressSpace::Stack.into()); let _stack_field_pointer_type = llvm.ptr_type(AddressSpace::Stack.into());
let heap_field_pointer_type = llvm.ptr_type(AddressSpace::Heap.into()); let heap_field_pointer_type = llvm.ptr_type(AddressSpace::Heap.into());
let generic_byte_pointer_type = llvm.ptr_type(AddressSpace::Generic.into()); let generic_byte_pointer_type = llvm.ptr_type(AddressSpace::Generic.into());
@@ -65,7 +64,7 @@ impl<'ctx> Intrinsics<'ctx> {
&[ &[
heap_field_pointer_type.as_basic_type_enum().into(), heap_field_pointer_type.as_basic_type_enum().into(),
heap_field_pointer_type.as_basic_type_enum().into(), heap_field_pointer_type.as_basic_type_enum().into(),
field_type.as_basic_type_enum().into(), word_type.as_basic_type_enum().into(),
bool_type.as_basic_type_enum().into(), bool_type.as_basic_type_enum().into(),
], ],
false, false,
@@ -79,30 +78,35 @@ impl<'ctx> Intrinsics<'ctx> {
&[ &[
heap_field_pointer_type.as_basic_type_enum().into(), heap_field_pointer_type.as_basic_type_enum().into(),
generic_byte_pointer_type.as_basic_type_enum().into(), generic_byte_pointer_type.as_basic_type_enum().into(),
field_type.as_basic_type_enum().into(), word_type.as_basic_type_enum().into(),
bool_type.as_basic_type_enum().into(), bool_type.as_basic_type_enum().into(),
], ],
false, false,
), ),
); );
let byte_swap = Self::declare( let byte_swap_word = Self::declare(
llvm, llvm,
module, module,
Self::FUNCTION_BYTE_SWAP, Self::FUNCTION_BYTE_SWAP_WORD,
field_type.fn_type(&[field_type.as_basic_type_enum().into()], false), word_type.fn_type(&[word_type.as_basic_type_enum().into()], false),
);
let byte_swap_eth_address = Self::declare(
llvm,
module,
Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS,
address_type.fn_type(&[address_type.as_basic_type_enum().into()], false),
); );
Self { Self {
trap, trap,
memory_copy, memory_copy,
memory_copy_from_generic, memory_copy_from_generic,
byte_swap, byte_swap_word,
byte_swap_eth_address,
} }
} }
///
/// Finds the specified LLVM intrinsic function in the target and returns its declaration. /// Finds the specified LLVM intrinsic function in the target and returns its declaration.
///
pub fn declare( pub fn declare(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>, module: &inkwell::module::Module<'ctx>,
@@ -118,14 +122,12 @@ impl<'ctx> Intrinsics<'ctx> {
FunctionDeclaration::new(r#type, value) FunctionDeclaration::new(r#type, value)
} }
///
/// Returns the LLVM types for selecting via the signature. /// Returns the LLVM types for selecting via the signature.
///
pub fn argument_types( pub fn argument_types(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
name: &str, name: &str,
) -> Vec<inkwell::types::BasicTypeEnum<'ctx>> { ) -> Vec<inkwell::types::BasicTypeEnum<'ctx>> {
let field_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32); let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32);
match name { match name {
name if name == Self::FUNCTION_MEMORY_COPY => vec![ name if name == Self::FUNCTION_MEMORY_COPY => vec![
@@ -133,16 +135,21 @@ impl<'ctx> Intrinsics<'ctx> {
.as_basic_type_enum(), .as_basic_type_enum(),
llvm.ptr_type(AddressSpace::Heap.into()) llvm.ptr_type(AddressSpace::Heap.into())
.as_basic_type_enum(), .as_basic_type_enum(),
field_type.as_basic_type_enum(), word_type.as_basic_type_enum(),
], ],
name if name == Self::FUNCTION_MEMORY_COPY_FROM_GENERIC => vec![ name if name == Self::FUNCTION_MEMORY_COPY_FROM_GENERIC => vec![
llvm.ptr_type(AddressSpace::Heap.into()) llvm.ptr_type(AddressSpace::Heap.into())
.as_basic_type_enum(), .as_basic_type_enum(),
llvm.ptr_type(AddressSpace::Generic.into()) llvm.ptr_type(AddressSpace::Generic.into())
.as_basic_type_enum(), .as_basic_type_enum(),
field_type.as_basic_type_enum(), word_type.as_basic_type_enum(),
], ],
name if name == Self::FUNCTION_BYTE_SWAP => vec![field_type.as_basic_type_enum()], name if name == Self::FUNCTION_BYTE_SWAP_WORD => vec![word_type.as_basic_type_enum()],
name if name == Self::FUNCTION_BYTE_SWAP_ETH_ADDRESS => {
vec![llvm
.custom_width_int_type(revive_common::BIT_LENGTH_ETH_ADDRESS as u32)
.as_basic_type_enum()]
}
_ => vec![], _ => vec![],
} }
} }
@@ -1,19 +1,14 @@
//!
//! The LLVM runtime functions. //! The LLVM runtime functions.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use crate::eravm::context::address_space::AddressSpace;
use crate::eravm::context::function::declaration::Declaration as FunctionDeclaration;
use crate::eravm::context::function::Function;
use crate::optimizer::Optimizer; use crate::optimizer::Optimizer;
use crate::polkavm::context::address_space::AddressSpace;
use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
use crate::polkavm::context::function::Function;
///
/// The runtime functions, implemented on the LLVM side. /// The runtime functions, implemented on the LLVM side.
///
/// The functions are automatically linked to the LLVM implementations if the signatures match. /// The functions are automatically linked to the LLVM implementations if the signatures match.
///
#[derive(Debug)] #[derive(Debug)]
pub struct LLVMRuntime<'ctx> { pub struct LLVMRuntime<'ctx> {
/// The LLVM personality function, used for exception handling. /// The LLVM personality function, used for exception handling.
@@ -21,15 +16,6 @@ pub struct LLVMRuntime<'ctx> {
/// The LLVM exception throwing function. /// The LLVM exception throwing function.
pub cxa_throw: FunctionDeclaration<'ctx>, pub cxa_throw: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function.
pub div: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function.
pub sdiv: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function.
pub r#mod: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function.
pub smod: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function. /// The corresponding LLVM runtime function.
pub shl: FunctionDeclaration<'ctx>, pub shl: FunctionDeclaration<'ctx>,
/// The corresponding LLVM runtime function. /// The corresponding LLVM runtime function.
@@ -87,18 +73,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
/// The LLVM exception throwing function name. /// The LLVM exception throwing function name.
pub const FUNCTION_CXA_THROW: &'static str = "__cxa_throw"; pub const FUNCTION_CXA_THROW: &'static str = "__cxa_throw";
/// The corresponding runtime function name.
pub const FUNCTION_DIV: &'static str = "__div";
/// The corresponding runtime function name.
pub const FUNCTION_SDIV: &'static str = "__sdiv";
/// The corresponding runtime function name.
pub const FUNCTION_MOD: &'static str = "__mod";
/// The corresponding runtime function name.
pub const FUNCTION_SMOD: &'static str = "__smod";
/// The corresponding runtime function name. /// The corresponding runtime function name.
pub const FUNCTION_SHL: &'static str = "__shl"; pub const FUNCTION_SHL: &'static str = "__shl";
@@ -159,9 +133,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
/// The corresponding runtime function name. /// The corresponding runtime function name.
pub const FUNCTION_REVERT: &'static str = "__revert"; pub const FUNCTION_REVERT: &'static str = "__revert";
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
module: &inkwell::module::Module<'ctx>, module: &inkwell::module::Module<'ctx>,
@@ -191,89 +163,13 @@ impl<'ctx> LLVMRuntime<'ctx> {
); );
Function::set_cxa_throw_attributes(llvm, cxa_throw); Function::set_cxa_throw_attributes(llvm, cxa_throw);
let div = Self::declare(
module,
Self::FUNCTION_DIV,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.fn_type(
vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.as_basic_type_enum()
.into();
2
]
.as_slice(),
false,
),
Some(inkwell::module::Linkage::External),
);
Function::set_default_attributes(llvm, div, optimizer);
Function::set_pure_function_attributes(llvm, div);
let r#mod = Self::declare(
module,
Self::FUNCTION_MOD,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.fn_type(
vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.as_basic_type_enum()
.into();
2
]
.as_slice(),
false,
),
Some(inkwell::module::Linkage::External),
);
Function::set_default_attributes(llvm, r#mod, optimizer);
Function::set_pure_function_attributes(llvm, r#mod);
let sdiv = Self::declare(
module,
Self::FUNCTION_SDIV,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.fn_type(
vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.as_basic_type_enum()
.into();
2
]
.as_slice(),
false,
),
Some(inkwell::module::Linkage::External),
);
Function::set_default_attributes(llvm, sdiv, optimizer);
Function::set_pure_function_attributes(llvm, sdiv);
let smod = Self::declare(
module,
Self::FUNCTION_SMOD,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.fn_type(
vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32)
.as_basic_type_enum()
.into();
2
]
.as_slice(),
false,
),
Some(inkwell::module::Linkage::External),
);
Function::set_default_attributes(llvm, smod, optimizer);
Function::set_pure_function_attributes(llvm, smod);
let shl = Self::declare( let shl = Self::declare(
module, module,
Self::FUNCTION_SHL, Self::FUNCTION_SHL,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type( .fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
2 2
@@ -289,10 +185,10 @@ impl<'ctx> LLVMRuntime<'ctx> {
let shr = Self::declare( let shr = Self::declare(
module, module,
Self::FUNCTION_SHR, Self::FUNCTION_SHR,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type( .fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
2 2
@@ -308,10 +204,10 @@ impl<'ctx> LLVMRuntime<'ctx> {
let sar = Self::declare( let sar = Self::declare(
module, module,
Self::FUNCTION_SAR, Self::FUNCTION_SAR,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type( .fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
2 2
@@ -327,10 +223,10 @@ impl<'ctx> LLVMRuntime<'ctx> {
let byte = Self::declare( let byte = Self::declare(
module, module,
Self::FUNCTION_BYTE, Self::FUNCTION_BYTE,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type( .fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
2 2
@@ -365,13 +261,13 @@ impl<'ctx> LLVMRuntime<'ctx> {
let sha3 = Self::declare( let sha3 = Self::declare(
module, module,
Self::FUNCTION_SHA3, Self::FUNCTION_SHA3,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type( .fn_type(
vec![ vec![
llvm.ptr_type(AddressSpace::Heap.into()) llvm.ptr_type(AddressSpace::Heap.into())
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_BOOLEAN as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_BOOLEAN as u32)
@@ -395,16 +291,16 @@ impl<'ctx> LLVMRuntime<'ctx> {
let system_request = Self::declare( let system_request = Self::declare(
module, module,
Self::FUNCTION_SYSTEM_REQUEST, Self::FUNCTION_SYSTEM_REQUEST,
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.fn_type( .fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
llvm.ptr_type(AddressSpace::Stack.into()) llvm.ptr_type(AddressSpace::Stack.into())
@@ -417,24 +313,17 @@ impl<'ctx> LLVMRuntime<'ctx> {
Some(inkwell::module::Linkage::External), Some(inkwell::module::Linkage::External),
); );
Function::set_default_attributes(llvm, system_request, optimizer); Function::set_default_attributes(llvm, system_request, optimizer);
Function::set_attributes(
llvm,
system_request,
//vec![Attribute::ArgMemOnly, Attribute::ReadOnly],
vec![],
false,
);
let external_call_arguments: Vec<inkwell::types::BasicMetadataTypeEnum> = vec![ let external_call_arguments: Vec<inkwell::types::BasicMetadataTypeEnum> = vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
crate::eravm::context::function::runtime::entry::Entry::MANDATORY_ARGUMENTS_COUNT crate::polkavm::context::function::runtime::entry::Entry::MANDATORY_ARGUMENTS_COUNT
+ crate::eravm::EXTRA_ABI_DATA_SIZE + crate::polkavm::EXTRA_ABI_DATA_SIZE
]; ];
let mut mimic_call_arguments = external_call_arguments.clone(); let mut mimic_call_arguments = external_call_arguments.clone();
mimic_call_arguments.push( mimic_call_arguments.push(
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
); );
@@ -443,21 +332,21 @@ impl<'ctx> LLVMRuntime<'ctx> {
llvm.ptr_type(AddressSpace::Generic.into()) llvm.ptr_type(AddressSpace::Generic.into())
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
]; ];
external_call_arguments_by_ref.extend::<Vec<inkwell::types::BasicMetadataTypeEnum>>(vec![ external_call_arguments_by_ref.extend::<Vec<inkwell::types::BasicMetadataTypeEnum>>(vec![
llvm.custom_width_int_type( llvm.custom_width_int_type(
revive_common::BIT_LENGTH_FIELD as u32 revive_common::BIT_LENGTH_WORD as u32
) )
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
crate::eravm::EXTRA_ABI_DATA_SIZE crate::polkavm::EXTRA_ABI_DATA_SIZE
]); ]);
let mut mimic_call_arguments_by_ref = external_call_arguments_by_ref.clone(); let mut mimic_call_arguments_by_ref = external_call_arguments_by_ref.clone();
mimic_call_arguments_by_ref.push( mimic_call_arguments_by_ref.push(
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(), .into(),
); );
@@ -536,7 +425,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
Self::FUNCTION_RETURN, Self::FUNCTION_RETURN,
llvm.void_type().fn_type( llvm.void_type().fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
3 3
@@ -552,7 +441,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
Self::FUNCTION_REVERT, Self::FUNCTION_REVERT,
llvm.void_type().fn_type( llvm.void_type().fn_type(
vec![ vec![
llvm.custom_width_int_type(revive_common::BIT_LENGTH_FIELD as u32) llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32)
.as_basic_type_enum() .as_basic_type_enum()
.into(); .into();
3 3
@@ -568,11 +457,6 @@ impl<'ctx> LLVMRuntime<'ctx> {
personality, personality,
cxa_throw, cxa_throw,
div,
sdiv,
r#mod,
smod,
shl, shl,
shr, shr,
sar, sar,
@@ -602,9 +486,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
} }
} }
///
/// Declares an LLVM runtime function in the `module`, /// Declares an LLVM runtime function in the `module`,
///
pub fn declare( pub fn declare(
module: &inkwell::module::Module<'ctx>, module: &inkwell::module::Module<'ctx>,
name: &str, name: &str,
@@ -625,9 +507,7 @@ impl<'ctx> LLVMRuntime<'ctx> {
FunctionDeclaration::new(value.get_type(), value).into() FunctionDeclaration::new(value.get_type(), value).into()
} }
///
/// Modifies the external call function with `is_byref` and `is_system` modifiers. /// Modifies the external call function with `is_byref` and `is_system` modifiers.
///
pub fn modify( pub fn modify(
&self, &self,
function: FunctionDeclaration<'ctx>, function: FunctionDeclaration<'ctx>,
@@ -1,6 +1,4 @@
//!
//! The LLVM IR generator function. //! The LLVM IR generator function.
//!
pub mod block; pub mod block;
pub mod declaration; pub mod declaration;
@@ -14,10 +12,10 @@ pub mod yul_data;
use std::collections::HashMap; use std::collections::HashMap;
use crate::eravm::context::attribute::Attribute;
use crate::eravm::context::pointer::Pointer;
use crate::optimizer::settings::size_level::SizeLevel; use crate::optimizer::settings::size_level::SizeLevel;
use crate::optimizer::Optimizer; use crate::optimizer::Optimizer;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::pointer::Pointer;
use self::declaration::Declaration; use self::declaration::Declaration;
use self::evmla_data::EVMLAData; use self::evmla_data::EVMLAData;
@@ -26,9 +24,7 @@ use self::runtime::Runtime;
use self::vyper_data::VyperData; use self::vyper_data::VyperData;
use self::yul_data::YulData; use self::yul_data::YulData;
///
/// The LLVM IR generator function. /// The LLVM IR generator function.
///
#[derive(Debug)] #[derive(Debug)]
pub struct Function<'ctx> { pub struct Function<'ctx> {
/// The high-level source code name. /// The high-level source code name.
@@ -66,9 +62,7 @@ impl<'ctx> Function<'ctx> {
/// The stack hashmap default capacity. /// The stack hashmap default capacity.
const STACK_HASHMAP_INITIAL_CAPACITY: usize = 64; const STACK_HASHMAP_INITIAL_CAPACITY: usize = 64;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
name: String, name: String,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
@@ -92,16 +86,12 @@ impl<'ctx> Function<'ctx> {
} }
} }
///
/// Returns the function name reference. /// Returns the function name reference.
///
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
self.name.as_str() self.name.as_str()
} }
///
/// Checks whether the function is defined outside of the front-end. /// Checks whether the function is defined outside of the front-end.
///
pub fn is_name_external(name: &str) -> bool { pub fn is_name_external(name: &str) -> bool {
name.starts_with("llvm.") name.starts_with("llvm.")
|| (name.starts_with("__") || (name.starts_with("__")
@@ -110,24 +100,18 @@ impl<'ctx> Function<'ctx> {
&& name != Runtime::FUNCTION_RUNTIME_CODE) && name != Runtime::FUNCTION_RUNTIME_CODE)
} }
///
/// Checks whether the function is related to the near call ABI. /// Checks whether the function is related to the near call ABI.
///
pub fn is_near_call_abi(name: &str) -> bool { pub fn is_near_call_abi(name: &str) -> bool {
name.starts_with(Self::ZKSYNC_NEAR_CALL_ABI_PREFIX) name.starts_with(Self::ZKSYNC_NEAR_CALL_ABI_PREFIX)
|| name == Self::ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER || name == Self::ZKSYNC_NEAR_CALL_ABI_EXCEPTION_HANDLER
} }
///
/// Returns the LLVM function declaration. /// Returns the LLVM function declaration.
///
pub fn declaration(&self) -> Declaration<'ctx> { pub fn declaration(&self) -> Declaration<'ctx> {
self.declaration self.declaration
} }
///
/// Returns the N-th parameter of the function. /// Returns the N-th parameter of the function.
///
pub fn get_nth_param(&self, index: usize) -> inkwell::values::BasicValueEnum<'ctx> { pub fn get_nth_param(&self, index: usize) -> inkwell::values::BasicValueEnum<'ctx> {
self.declaration() self.declaration()
.value .value
@@ -135,9 +119,7 @@ impl<'ctx> Function<'ctx> {
.expect("Always exists") .expect("Always exists")
} }
///
/// Sets the memory writer function attributes. /// Sets the memory writer function attributes.
///
pub fn set_attributes( pub fn set_attributes(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
@@ -146,6 +128,7 @@ impl<'ctx> Function<'ctx> {
) { ) {
for attribute_kind in attributes.into_iter() { for attribute_kind in attributes.into_iter() {
match attribute_kind { match attribute_kind {
Attribute::Memory => todo!("`memory` attributes are not yet implemented"),
attribute_kind @ Attribute::AlwaysInline if force => { attribute_kind @ Attribute::AlwaysInline if force => {
let is_optimize_none_set = declaration let is_optimize_none_set = declaration
.value .value
@@ -183,17 +166,36 @@ impl<'ctx> Function<'ctx> {
} }
} }
/// /// Remove specified attributes existing on the given declaration.
pub fn remove_attributes(declaration: Declaration, attributes: &[Attribute]) {
for attribute in attributes.iter().filter(|attribute| {
declaration
.value
.get_enum_attribute(
inkwell::attributes::AttributeLoc::Function,
**attribute as u32,
)
.is_some()
}) {
declaration.value.remove_enum_attribute(
inkwell::attributes::AttributeLoc::Function,
*attribute as u32,
);
}
}
/// Sets the default attributes. /// Sets the default attributes.
///
/// The attributes only affect the LLVM optimizations. /// The attributes only affect the LLVM optimizations.
///
pub fn set_default_attributes( pub fn set_default_attributes(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
optimizer: &Optimizer, optimizer: &Optimizer,
) { ) {
if optimizer.settings().level_middle_end == inkwell::OptimizationLevel::None { if optimizer.settings().level_middle_end == inkwell::OptimizationLevel::None {
Self::remove_attributes(
declaration,
&[Attribute::OptimizeForSize, Attribute::AlwaysInline],
);
Self::set_attributes( Self::set_attributes(
llvm, llvm,
declaration, declaration,
@@ -212,9 +214,7 @@ impl<'ctx> Function<'ctx> {
Self::set_attributes(llvm, declaration, vec![Attribute::NoFree], false); Self::set_attributes(llvm, declaration, vec![Attribute::NoFree], false);
} }
///
/// Sets the front-end runtime attributes. /// Sets the front-end runtime attributes.
///
pub fn set_frontend_runtime_attributes( pub fn set_frontend_runtime_attributes(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
@@ -225,9 +225,7 @@ impl<'ctx> Function<'ctx> {
} }
} }
///
/// Sets the exception handler attributes. /// Sets the exception handler attributes.
///
pub fn set_exception_handler_attributes( pub fn set_exception_handler_attributes(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
@@ -235,9 +233,7 @@ impl<'ctx> Function<'ctx> {
Self::set_attributes(llvm, declaration, vec![Attribute::NoInline], false); Self::set_attributes(llvm, declaration, vec![Attribute::NoInline], false);
} }
///
/// Sets the CXA-throw attributes. /// Sets the CXA-throw attributes.
///
pub fn set_cxa_throw_attributes( pub fn set_cxa_throw_attributes(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
@@ -245,9 +241,7 @@ impl<'ctx> Function<'ctx> {
Self::set_attributes(llvm, declaration, vec![Attribute::NoProfile], false); Self::set_attributes(llvm, declaration, vec![Attribute::NoProfile], false);
} }
///
/// Sets the pure function attributes. /// Sets the pure function attributes.
///
pub fn set_pure_function_attributes( pub fn set_pure_function_attributes(
llvm: &'ctx inkwell::context::Context, llvm: &'ctx inkwell::context::Context,
declaration: Declaration<'ctx>, declaration: Declaration<'ctx>,
@@ -258,18 +252,14 @@ impl<'ctx> Function<'ctx> {
vec![ vec![
Attribute::MustProgress, Attribute::MustProgress,
Attribute::NoUnwind, Attribute::NoUnwind,
// FIXME: LLVM complains about ReadNone being not valid for fns
// Attribute::ReadNone,
Attribute::WillReturn, Attribute::WillReturn,
], ],
false, false,
); );
} }
///
/// Saves the pointer to a stack variable, returning the pointer to the shadowed variable, /// Saves the pointer to a stack variable, returning the pointer to the shadowed variable,
/// if it exists. /// if it exists.
///
pub fn insert_stack_pointer( pub fn insert_stack_pointer(
&mut self, &mut self,
name: String, name: String,
@@ -278,148 +268,108 @@ impl<'ctx> Function<'ctx> {
self.stack.insert(name, pointer) self.stack.insert(name, pointer)
} }
///
/// Gets the pointer to a stack variable. /// Gets the pointer to a stack variable.
///
pub fn get_stack_pointer(&self, name: &str) -> Option<Pointer<'ctx>> { pub fn get_stack_pointer(&self, name: &str) -> Option<Pointer<'ctx>> {
self.stack.get(name).copied() self.stack.get(name).copied()
} }
///
/// Removes the pointer to a stack variable. /// Removes the pointer to a stack variable.
///
pub fn remove_stack_pointer(&mut self, name: &str) { pub fn remove_stack_pointer(&mut self, name: &str) {
self.stack.remove(name); self.stack.remove(name);
} }
///
/// Returns the return entity representation. /// Returns the return entity representation.
///
pub fn r#return(&self) -> Return<'ctx> { pub fn r#return(&self) -> Return<'ctx> {
self.r#return self.r#return
} }
///
/// Returns the pointer to the function return value. /// Returns the pointer to the function return value.
///
/// # Panics /// # Panics
/// If the pointer has not been set yet. /// If the pointer has not been set yet.
///
pub fn return_pointer(&self) -> Option<Pointer<'ctx>> { pub fn return_pointer(&self) -> Option<Pointer<'ctx>> {
self.r#return.return_pointer() self.r#return.return_pointer()
} }
///
/// Returns the return data size in bytes, based on the default stack alignment. /// Returns the return data size in bytes, based on the default stack alignment.
///
/// # Panics /// # Panics
/// If the pointer has not been set yet. /// If the pointer has not been set yet.
///
pub fn return_data_size(&self) -> usize { pub fn return_data_size(&self) -> usize {
self.r#return.return_data_size() self.r#return.return_data_size()
} }
///
/// Returns the function entry block. /// Returns the function entry block.
///
pub fn entry_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> { pub fn entry_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.entry_block self.entry_block
} }
///
/// Returns the function return block. /// Returns the function return block.
///
pub fn return_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> { pub fn return_block(&self) -> inkwell::basic_block::BasicBlock<'ctx> {
self.return_block self.return_block
} }
///
/// Sets the EVM legacy assembly data. /// Sets the EVM legacy assembly data.
///
pub fn set_evmla_data(&mut self, data: EVMLAData<'ctx>) { pub fn set_evmla_data(&mut self, data: EVMLAData<'ctx>) {
self.evmla_data = Some(data); self.evmla_data = Some(data);
} }
///
/// Returns the EVM legacy assembly data reference. /// Returns the EVM legacy assembly data reference.
///
/// # Panics /// # Panics
/// If the EVM data has not been initialized. /// If the EVM data has not been initialized.
///
pub fn evmla(&self) -> &EVMLAData<'ctx> { pub fn evmla(&self) -> &EVMLAData<'ctx> {
self.evmla_data self.evmla_data
.as_ref() .as_ref()
.expect("The EVM data must have been initialized") .expect("The EVM data must have been initialized")
} }
///
/// Returns the EVM legacy assembly data mutable reference. /// Returns the EVM legacy assembly data mutable reference.
///
/// # Panics /// # Panics
/// If the EVM data has not been initialized. /// If the EVM data has not been initialized.
///
pub fn evmla_mut(&mut self) -> &mut EVMLAData<'ctx> { pub fn evmla_mut(&mut self) -> &mut EVMLAData<'ctx> {
self.evmla_data self.evmla_data
.as_mut() .as_mut()
.expect("The EVM data must have been initialized") .expect("The EVM data must have been initialized")
} }
///
/// Sets the Vyper data. /// Sets the Vyper data.
///
pub fn set_vyper_data(&mut self, data: VyperData) { pub fn set_vyper_data(&mut self, data: VyperData) {
self.vyper_data = Some(data); self.vyper_data = Some(data);
} }
///
/// Returns the Vyper data reference. /// Returns the Vyper data reference.
///
/// # Panics /// # Panics
/// If the Vyper data has not been initialized. /// If the Vyper data has not been initialized.
///
pub fn vyper(&self) -> &VyperData { pub fn vyper(&self) -> &VyperData {
self.vyper_data self.vyper_data
.as_ref() .as_ref()
.expect("The Vyper data must have been initialized") .expect("The Vyper data must have been initialized")
} }
///
/// Returns the Vyper data mutable reference. /// Returns the Vyper data mutable reference.
///
/// # Panics /// # Panics
/// If the Vyper data has not been initialized. /// If the Vyper data has not been initialized.
///
pub fn vyper_mut(&mut self) -> &mut VyperData { pub fn vyper_mut(&mut self) -> &mut VyperData {
self.vyper_data self.vyper_data
.as_mut() .as_mut()
.expect("The Vyper data must have been initialized") .expect("The Vyper data must have been initialized")
} }
///
/// Sets the Yul data. /// Sets the Yul data.
///
pub fn set_yul_data(&mut self, data: YulData) { pub fn set_yul_data(&mut self, data: YulData) {
self.yul_data = Some(data); self.yul_data = Some(data);
} }
///
/// Returns the Yul data reference. /// Returns the Yul data reference.
///
/// # Panics /// # Panics
/// If the Yul data has not been initialized. /// If the Yul data has not been initialized.
///
pub fn yul(&self) -> &YulData { pub fn yul(&self) -> &YulData {
self.yul_data self.yul_data
.as_ref() .as_ref()
.expect("The Yul data must have been initialized") .expect("The Yul data must have been initialized")
} }
///
/// Returns the Yul data mutable reference. /// Returns the Yul data mutable reference.
///
/// # Panics /// # Panics
/// If the Yul data has not been initialized. /// If the Yul data has not been initialized.
///
pub fn yul_mut(&mut self) -> &mut YulData { pub fn yul_mut(&mut self) -> &mut YulData {
self.yul_data self.yul_data
.as_mut() .as_mut()
@@ -1,12 +1,8 @@
//!
//! The LLVM IR generator function return entity. //! The LLVM IR generator function return entity.
//!
use crate::eravm::context::pointer::Pointer; use crate::polkavm::context::pointer::Pointer;
///
/// The LLVM IR generator function return entity. /// The LLVM IR generator function return entity.
///
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Return<'ctx> { pub enum Return<'ctx> {
/// The function does not return a value. /// The function does not return a value.
@@ -27,30 +23,22 @@ pub enum Return<'ctx> {
} }
impl<'ctx> Return<'ctx> { impl<'ctx> Return<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn none() -> Self { pub fn none() -> Self {
Self::None Self::None
} }
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn primitive(pointer: Pointer<'ctx>) -> Self { pub fn primitive(pointer: Pointer<'ctx>) -> Self {
Self::Primitive { pointer } Self::Primitive { pointer }
} }
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn compound(pointer: Pointer<'ctx>, size: usize) -> Self { pub fn compound(pointer: Pointer<'ctx>, size: usize) -> Self {
Self::Compound { pointer, size } Self::Compound { pointer, size }
} }
///
/// Returns the pointer to the function return value. /// Returns the pointer to the function return value.
///
pub fn return_pointer(&self) -> Option<Pointer<'ctx>> { pub fn return_pointer(&self) -> Option<Pointer<'ctx>> {
match self { match self {
Return::None => None, Return::None => None,
@@ -59,11 +47,9 @@ impl<'ctx> Return<'ctx> {
} }
} }
///
/// Returns the return data size in bytes, based on the default stack alignment. /// Returns the return data size in bytes, based on the default stack alignment.
///
pub fn return_data_size(&self) -> usize { pub fn return_data_size(&self) -> usize {
revive_common::BYTE_LENGTH_FIELD revive_common::BYTE_LENGTH_WORD
* match self { * match self {
Self::None => 0, Self::None => 0,
Self::Primitive { .. } => 1, Self::Primitive { .. } => 1,
@@ -1,21 +1,16 @@
//!
//! The `default_call` function. //! The `default_call` function.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use crate::eravm::context::function::declaration::Declaration as FunctionDeclaration; use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
use crate::eravm::context::function::llvm_runtime::LLVMRuntime; use crate::polkavm::context::function::llvm_runtime::LLVMRuntime;
use crate::eravm::context::function::Function; use crate::polkavm::context::function::Function;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
use crate::eravm::WriteLLVM; use crate::polkavm::WriteLLVM;
///
/// The `default_call` function. /// The `default_call` function.
///
/// Generates a default contract call, if the `msg.value` is zero. /// Generates a default contract call, if the `msg.value` is zero.
///
#[derive(Debug)] #[derive(Debug)]
pub struct DefaultCall { pub struct DefaultCall {
/// The name of the inner function used for the low-level call. /// The name of the inner function used for the low-level call.
@@ -44,9 +39,7 @@ impl DefaultCall {
/// The output length argument index. /// The output length argument index.
pub const ARGUMENT_INDEX_OUTPUT_LENGTH: usize = 5; pub const ARGUMENT_INDEX_OUTPUT_LENGTH: usize = 5;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(call_function: FunctionDeclaration) -> Self { pub fn new(call_function: FunctionDeclaration) -> Self {
let inner_name = call_function.value.get_name().to_string_lossy().to_string(); let inner_name = call_function.value.get_name().to_string_lossy().to_string();
let name = Self::name(call_function); let name = Self::name(call_function);
@@ -54,9 +47,7 @@ impl DefaultCall {
Self { inner_name, name } Self { inner_name, name }
} }
///
/// Returns the function name. /// Returns the function name.
///
pub fn name(call_function: FunctionDeclaration) -> String { pub fn name(call_function: FunctionDeclaration) -> String {
let suffix = match call_function.value.get_name().to_string_lossy() { let suffix = match call_function.value.get_name().to_string_lossy() {
name if name == LLVMRuntime::FUNCTION_FARCALL => "far", name if name == LLVMRuntime::FUNCTION_FARCALL => "far",
@@ -67,9 +58,7 @@ impl DefaultCall {
format!("__default_{suffix}_call") format!("__default_{suffix}_call")
} }
///
/// Returns the low-level call function. /// Returns the low-level call function.
///
fn inner_function<'ctx, D>(&self, context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx> fn inner_function<'ctx, D>(&self, context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx>
where where
D: Dependency + Clone, D: Dependency + Clone,
@@ -92,12 +81,12 @@ where
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> { fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
let function_type = context.function_type( let function_type = context.function_type(
vec![ vec![
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
], ],
1, 1,
false, false,
@@ -155,13 +144,13 @@ where
context.set_basic_block(context.current_function().borrow().entry_block()); context.set_basic_block(context.current_function().borrow().entry_block());
let status_code_result_pointer = context.build_alloca( let status_code_result_pointer = context.build_alloca(
context.field_type(), context.word_type(),
"contract_call_result_status_code_pointer", "contract_call_result_status_code_pointer",
); );
/* /*
context.build_store(status_code_result_pointer, context.field_const(0)); context.build_store(status_code_result_pointer, context.field_const(0));
let abi_data = crate::eravm::utils::abi_data( let abi_data = crate::polkavm::utils::abi_data(
context, context,
input_offset, input_offset,
input_length, input_length,
@@ -174,7 +163,7 @@ where
let result = context let result = context
.build_call( .build_call(
self.inner_function(context), self.inner_function(context),
crate::eravm::utils::external_call_arguments( crate::polkavm::utils::external_call_arguments(
context, context,
abi_data.as_basic_value_enum(), abi_data.as_basic_value_enum(),
address, address,
@@ -236,11 +225,11 @@ where
context.write_abi_pointer( context.write_abi_pointer(
result_abi_data_pointer, result_abi_data_pointer,
crate::eravm::GLOBAL_RETURN_DATA_POINTER, crate::polkavm::GLOBAL_RETURN_DATA_POINTER,
); );
context.write_abi_data_size( context.write_abi_data_size(
result_abi_data_pointer, result_abi_data_pointer,
crate::eravm::GLOBAL_RETURN_DATA_SIZE, crate::polkavm::GLOBAL_RETURN_DATA_SIZE,
); );
*/ */
context.build_unconditional_branch(context.current_function().borrow().return_block()); context.build_unconditional_branch(context.current_function().borrow().return_block());
@@ -1,22 +1,17 @@
//!
//! The deploy code function. //! The deploy code function.
//!
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::code_type::CodeType; use crate::polkavm::context::code_type::CodeType;
use crate::eravm::context::function::runtime::Runtime; use crate::polkavm::context::function::runtime::Runtime;
use crate::eravm::context::pointer::Pointer; use crate::polkavm::context::pointer::Pointer;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
use crate::eravm::WriteLLVM; use crate::polkavm::WriteLLVM;
///
/// The deploy code function. /// The deploy code function.
///
/// Is a special function that is only used by the front-end generated code. /// Is a special function that is only used by the front-end generated code.
///
#[derive(Debug)] #[derive(Debug)]
pub struct DeployCode<B, D> pub struct DeployCode<B, D>
where where
@@ -34,9 +29,7 @@ where
B: WriteLLVM<D>, B: WriteLLVM<D>,
D: Dependency + Clone, D: Dependency + Clone,
{ {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(inner: B) -> Self { pub fn new(inner: B) -> Self {
Self { Self {
inner, inner,
@@ -69,19 +62,19 @@ where
context.set_basic_block(context.current_function().borrow().entry_block()); context.set_basic_block(context.current_function().borrow().entry_block());
context.set_code_type(CodeType::Deploy); context.set_code_type(CodeType::Deploy);
if let Some(vyper) = context.vyper_data.as_ref() { if let Some(vyper) = context.vyper_data.as_ref() {
for index in 0..vyper.immutables_size() / revive_common::BYTE_LENGTH_FIELD { for index in 0..vyper.immutables_size() / revive_common::BYTE_LENGTH_WORD {
let offset = (crate::eravm::r#const::HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA let offset = (crate::polkavm::r#const::HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA
as usize) as usize)
+ (1 + index) * 2 * revive_common::BYTE_LENGTH_FIELD; + (1 + index) * 2 * revive_common::BYTE_LENGTH_WORD;
let value = index * revive_common::BYTE_LENGTH_FIELD; let value = index * revive_common::BYTE_LENGTH_WORD;
let pointer = Pointer::new_with_offset( let pointer = Pointer::new_with_offset(
context, context,
AddressSpace::HeapAuxiliary, AddressSpace::HeapAuxiliary,
context.field_type(), context.word_type(),
context.field_const(offset as u64), context.word_const(offset as u64),
"immutable_index_initializer", "immutable_index_initializer",
); );
context.build_store(pointer, context.field_const(value as u64))?; context.build_store(pointer, context.word_const(value as u64))?;
} }
} }
@@ -1,24 +1,18 @@
//!
//! The `deployer_call` function. //! The `deployer_call` function.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::function::Function; use crate::polkavm::context::function::Function;
use crate::eravm::context::pointer::Pointer; use crate::polkavm::context::pointer::Pointer;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
use crate::eravm::WriteLLVM; use crate::polkavm::WriteLLVM;
///
/// The `deployer_call` function. /// The `deployer_call` function.
///
/// Calls the deployer system contract, which returns the newly deployed contract address or 0. /// Calls the deployer system contract, which returns the newly deployed contract address or 0.
///
/// The address is returned in the first 32-byte word of the return data. If it is 0, the 0 is /// The address is returned in the first 32-byte word of the return data. If it is 0, the 0 is
/// returned. If the entire call has failed, there is also a 0 returned. /// returned. If the entire call has failed, there is also a 0 returned.
///
#[derive(Debug)] #[derive(Debug)]
pub struct DeployerCall { pub struct DeployerCall {
/// The address space where the calldata is allocated. /// The address space where the calldata is allocated.
@@ -45,9 +39,7 @@ impl DeployerCall {
/// The salt argument index. /// The salt argument index.
pub const ARGUMENT_INDEX_SALT: usize = 4; pub const ARGUMENT_INDEX_SALT: usize = 4;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(address_space: AddressSpace) -> Self { pub fn new(address_space: AddressSpace) -> Self {
Self { address_space } Self { address_space }
} }
@@ -60,11 +52,11 @@ where
fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> { fn declare(&mut self, context: &mut Context<D>) -> anyhow::Result<()> {
let function_type = context.function_type( let function_type = context.function_type(
vec![ vec![
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
], ],
1, 1,
false, false,
@@ -120,7 +112,7 @@ where
let value_join_block = context.append_basic_block("deployer_call_value_join_block"); let value_join_block = context.append_basic_block("deployer_call_value_join_block");
context.set_basic_block(context.current_function().borrow().entry_block()); context.set_basic_block(context.current_function().borrow().entry_block());
let _abi_data = crate::eravm::utils::abi_data( let _abi_data = crate::polkavm::utils::abi_data(
context, context,
input_offset, input_offset,
input_length, input_length,
@@ -132,7 +124,7 @@ where
let signature_pointer = Pointer::new_with_offset( let signature_pointer = Pointer::new_with_offset(
context, context,
self.address_space, self.address_space,
context.field_type(), context.word_type(),
input_offset, input_offset,
"deployer_call_signature_pointer", "deployer_call_signature_pointer",
); );
@@ -140,13 +132,13 @@ where
let salt_offset = context.builder().build_int_add( let salt_offset = context.builder().build_int_add(
input_offset, input_offset,
context.field_const(revive_common::BYTE_LENGTH_X32 as u64), context.word_const(revive_common::BYTE_LENGTH_X32 as u64),
"deployer_call_salt_offset", "deployer_call_salt_offset",
)?; )?;
let salt_pointer = Pointer::new_with_offset( let salt_pointer = Pointer::new_with_offset(
context, context,
self.address_space, self.address_space,
context.field_type(), context.word_type(),
salt_offset, salt_offset,
"deployer_call_salt_pointer", "deployer_call_salt_pointer",
); );
@@ -154,47 +146,47 @@ where
let arguments_offset_offset = context.builder().build_int_add( let arguments_offset_offset = context.builder().build_int_add(
salt_offset, salt_offset,
context.field_const((revive_common::BYTE_LENGTH_FIELD * 2) as u64), context.word_const((revive_common::BYTE_LENGTH_WORD * 2) as u64),
"deployer_call_arguments_offset_offset", "deployer_call_arguments_offset_offset",
)?; )?;
let arguments_offset_pointer = Pointer::new_with_offset( let arguments_offset_pointer = Pointer::new_with_offset(
context, context,
self.address_space, self.address_space,
context.field_type(), context.word_type(),
arguments_offset_offset, arguments_offset_offset,
"deployer_call_arguments_offset_pointer", "deployer_call_arguments_offset_pointer",
); );
context.build_store( context.build_store(
arguments_offset_pointer, arguments_offset_pointer,
context.field_const( context.word_const(
(crate::eravm::DEPLOYER_CALL_HEADER_SIZE (crate::polkavm::DEPLOYER_CALL_HEADER_SIZE
- (revive_common::BYTE_LENGTH_X32 + revive_common::BYTE_LENGTH_FIELD)) - (revive_common::BYTE_LENGTH_X32 + revive_common::BYTE_LENGTH_WORD))
as u64, as u64,
), ),
)?; )?;
let arguments_length_offset = context.builder().build_int_add( let arguments_length_offset = context.builder().build_int_add(
arguments_offset_offset, arguments_offset_offset,
context.field_const(revive_common::BYTE_LENGTH_FIELD as u64), context.word_const(revive_common::BYTE_LENGTH_WORD as u64),
"deployer_call_arguments_length_offset", "deployer_call_arguments_length_offset",
)?; )?;
let arguments_length_pointer = Pointer::new_with_offset( let arguments_length_pointer = Pointer::new_with_offset(
context, context,
self.address_space, self.address_space,
context.field_type(), context.word_type(),
arguments_length_offset, arguments_length_offset,
"deployer_call_arguments_length_pointer", "deployer_call_arguments_length_pointer",
); );
let arguments_length_value = context.builder().build_int_sub( let arguments_length_value = context.builder().build_int_sub(
input_length, input_length,
context.field_const(crate::eravm::DEPLOYER_CALL_HEADER_SIZE as u64), context.word_const(crate::polkavm::DEPLOYER_CALL_HEADER_SIZE as u64),
"deployer_call_arguments_length", "deployer_call_arguments_length",
)?; )?;
context.build_store(arguments_length_pointer, arguments_length_value)?; context.build_store(arguments_length_pointer, arguments_length_value)?;
let result_pointer = let result_pointer =
context.build_alloca(context.field_type(), "deployer_call_result_pointer"); context.build_alloca(context.word_type(), "deployer_call_result_pointer");
context.build_store(result_pointer, context.field_const(0))?; context.build_store(result_pointer, context.word_const(0))?;
let deployer_call_result_type = context.structure_type(&[ let deployer_call_result_type = context.structure_type(&[
context context
.llvm() .llvm()
@@ -211,7 +203,7 @@ where
let is_value_zero = context.builder().build_int_compare( let is_value_zero = context.builder().build_int_compare(
inkwell::IntPredicate::EQ, inkwell::IntPredicate::EQ,
value, value,
context.field_const(0), context.word_const(0),
"deployer_call_is_value_zero", "deployer_call_is_value_zero",
)?; )?;
context.build_conditional_branch(is_value_zero, value_zero_block, value_non_zero_block)?; context.build_conditional_branch(is_value_zero, value_zero_block, value_non_zero_block)?;
@@ -220,7 +212,7 @@ where
//let deployer_call_result = context //let deployer_call_result = context
// .build_call( // .build_call(
// context.llvm_runtime().far_call, // context.llvm_runtime().far_call,
// crate::eravm::utils::external_call_arguments( // crate::polkavm::utils::external_call_arguments(
// context, // context,
// abi_data, // abi_data,
// context.field_const(zkevm_opcode_defs::ADDRESS_CONTRACT_DEPLOYER.into()), // context.field_const(zkevm_opcode_defs::ADDRESS_CONTRACT_DEPLOYER.into()),
@@ -238,14 +230,14 @@ where
//let deployer_call_result = context //let deployer_call_result = context
// .build_call( // .build_call(
// context.llvm_runtime().far_call, // context.llvm_runtime().far_call,
// crate::eravm::utils::external_call_arguments( // crate::polkavm::utils::external_call_arguments(
// context, // context,
// abi_data.as_basic_value_enum(), // abi_data.as_basic_value_enum(),
// context.field_const(zkevm_opcode_defs::ADDRESS_MSG_VALUE.into()), // context.field_const(zkevm_opcode_defs::ADDRESS_MSG_VALUE.into()),
// vec![ // vec![
// value, // value,
// context.field_const(zkevm_opcode_defs::ADDRESS_CONTRACT_DEPLOYER.into()), // context.field_const(zkevm_opcode_defs::ADDRESS_CONTRACT_DEPLOYER.into()),
// context.field_const(u64::from(crate::eravm::r#const::SYSTEM_CALL_BIT)), // context.field_const(u64::from(crate::polkavm::r#const::SYSTEM_CALL_BIT)),
// ], // ],
// None, // None,
// ) // )
@@ -260,7 +252,7 @@ where
let result_abi_data_pointer = context.build_gep( let result_abi_data_pointer = context.build_gep(
deployer_call_result_pointer, deployer_call_result_pointer,
&[ &[
context.field_const(0), context.word_const(0),
context context
.integer_type(revive_common::BIT_LENGTH_X32) .integer_type(revive_common::BIT_LENGTH_X32)
.const_zero(), .const_zero(),
@@ -277,7 +269,7 @@ where
let result_status_code_pointer = context.build_gep( let result_status_code_pointer = context.build_gep(
deployer_call_result_pointer, deployer_call_result_pointer,
&[ &[
context.field_const(0), context.word_const(0),
context context
.integer_type(revive_common::BIT_LENGTH_X32) .integer_type(revive_common::BIT_LENGTH_X32)
.const_int(1, false), .const_int(1, false),
@@ -296,7 +288,7 @@ where
context.set_basic_block(success_block); context.set_basic_block(success_block);
let result_abi_data_pointer = Pointer::new( let result_abi_data_pointer = Pointer::new(
context.field_type(), context.word_type(),
AddressSpace::Generic, AddressSpace::Generic,
result_abi_data.into_pointer_value(), result_abi_data.into_pointer_value(),
); );
@@ -315,11 +307,11 @@ where
); );
context.write_abi_pointer( context.write_abi_pointer(
result_abi_data_pointer, result_abi_data_pointer,
crate::eravm::GLOBAL_RETURN_DATA_POINTER, crate::polkavm::GLOBAL_RETURN_DATA_POINTER,
); );
context.write_abi_data_size( context.write_abi_data_size(
result_abi_data_pointer, result_abi_data_pointer,
crate::eravm::GLOBAL_RETURN_DATA_SIZE, crate::polkavm::GLOBAL_RETURN_DATA_SIZE,
); );
context.build_unconditional_branch(context.current_function().borrow().return_block()); context.build_unconditional_branch(context.current_function().borrow().return_block());
@@ -1,23 +1,18 @@
//!
//! The entry function. //! The entry function.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::function::runtime::Runtime; use crate::polkavm::context::function::runtime::Runtime;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::r#const::*;
use crate::eravm::WriteLLVM; use crate::polkavm::Dependency;
use crate::EraVMPointer as Pointer; use crate::polkavm::WriteLLVM;
use crate::PolkaVMPointer as Pointer;
///
/// The entry function. /// The entry function.
///
/// The function is a wrapper managing the runtime and deploy code calling logic. /// The function is a wrapper managing the runtime and deploy code calling logic.
///
/// Is a special runtime function that is only used by the front-end generated code. /// Is a special runtime function that is only used by the front-end generated code.
///
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Entry {} pub struct Entry {}
@@ -39,56 +34,83 @@ impl Entry {
{ {
let calldata_type = context.array_type(context.byte_type(), Self::MAX_CALLDATA_SIZE); let calldata_type = context.array_type(context.byte_type(), Self::MAX_CALLDATA_SIZE);
context.set_global( context.set_global(
crate::eravm::GLOBAL_CALLDATA_POINTER, crate::polkavm::GLOBAL_CALLDATA_POINTER,
calldata_type, calldata_type,
AddressSpace::Stack, AddressSpace::Stack,
calldata_type.get_undef(), calldata_type.get_undef(),
); );
context.set_global( context.set_global(
crate::eravm::GLOBAL_HEAP_MEMORY_POINTER, crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER,
context.llvm().ptr_type(AddressSpace::Generic.into()), context.llvm().ptr_type(AddressSpace::Generic.into()),
AddressSpace::Stack, AddressSpace::Stack,
context.xlen_type().get_undef(), context.xlen_type().get_undef(),
); );
context.build_store( context.build_store(
context context
.get_global(crate::eravm::GLOBAL_HEAP_MEMORY_POINTER)? .get_global(crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER)?
.into(), .into(),
context.build_sbrk(context.integer_const(32, 0))?, context.build_sbrk(context.integer_const(crate::polkavm::XLEN, 0))?,
)?; )?;
context.set_global( context.set_global(
crate::eravm::GLOBAL_CALLDATA_SIZE, crate::polkavm::GLOBAL_CALLDATA_SIZE,
context.field_type(), context.word_type(),
AddressSpace::Stack, AddressSpace::Stack,
context.field_undef(), context.word_undef(),
); );
context.set_global( context.set_global(
crate::eravm::GLOBAL_RETURN_DATA_SIZE, crate::polkavm::GLOBAL_RETURN_DATA_SIZE,
context.field_type(), context.word_type(),
AddressSpace::Stack, AddressSpace::Stack,
context.field_const(0), context.word_const(0),
); );
context.set_global( context.set_global(
crate::eravm::GLOBAL_CALL_FLAGS, crate::polkavm::GLOBAL_CALL_FLAGS,
context.field_type(), context.word_type(),
AddressSpace::Stack, AddressSpace::Stack,
context.field_const(0), context.word_const(0),
); );
let extra_abi_data_type = context.array_type( let extra_abi_data_type = context.array_type(
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
crate::eravm::EXTRA_ABI_DATA_SIZE, crate::polkavm::EXTRA_ABI_DATA_SIZE,
); );
context.set_global( context.set_global(
crate::eravm::GLOBAL_EXTRA_ABI_DATA, crate::polkavm::GLOBAL_EXTRA_ABI_DATA,
extra_abi_data_type, extra_abi_data_type,
AddressSpace::Stack, AddressSpace::Stack,
extra_abi_data_type.const_zero(), extra_abi_data_type.const_zero(),
); );
context.set_global(
crate::polkavm::GLOBAL_I256_SIZE,
context.xlen_type(),
AddressSpace::Stack,
context.integer_const(
crate::polkavm::XLEN,
revive_common::BYTE_LENGTH_X64 as u64 * 4,
),
);
context.set_global(
crate::polkavm::GLOBAL_I160_SIZE,
context.xlen_type(),
AddressSpace::Stack,
context.integer_const(
crate::polkavm::XLEN,
revive_common::BYTE_LENGTH_X64 as u64 * 2 + revive_common::BYTE_LENGTH_X32 as u64,
),
);
context.set_global(
crate::polkavm::GLOBAL_I64_SIZE,
context.xlen_type(),
AddressSpace::Stack,
context.integer_const(crate::polkavm::XLEN, revive_common::BYTE_LENGTH_X64 as u64),
);
Ok(()) Ok(())
} }
@@ -99,7 +121,7 @@ impl Entry {
D: Dependency + Clone, D: Dependency + Clone,
{ {
let input_pointer = context let input_pointer = context
.get_global(crate::eravm::GLOBAL_CALLDATA_POINTER)? .get_global(crate::polkavm::GLOBAL_CALLDATA_POINTER)?
.value .value
.as_pointer_value(); .as_pointer_value();
let input_pointer_casted = context.builder.build_ptr_to_int( let input_pointer_casted = context.builder.build_ptr_to_int(
@@ -117,13 +139,12 @@ impl Entry {
context.build_store( context.build_store(
length_pointer, length_pointer,
context.integer_const(32, Self::MAX_CALLDATA_SIZE as u64), context.integer_const(crate::polkavm::XLEN, Self::MAX_CALLDATA_SIZE as u64),
)?; )?;
context.builder().build_call( context.build_runtime_call(
context.module().get_function("input").expect("is declared"), runtime_api::INPUT,
&[input_pointer_casted.into(), length_pointer_casted.into()], &[input_pointer_casted.into(), length_pointer_casted.into()],
"call_seal_input", );
)?;
// Store the calldata size // Store the calldata size
let calldata_size = context let calldata_size = context
@@ -131,12 +152,12 @@ impl Entry {
.into_int_value(); .into_int_value();
let calldata_size_casted = context.builder().build_int_z_extend( let calldata_size_casted = context.builder().build_int_z_extend(
calldata_size, calldata_size,
context.field_type(), context.word_type(),
"zext_input_len", "zext_input_len",
)?; )?;
context.set_global( context.set_global(
crate::eravm::GLOBAL_CALLDATA_SIZE, crate::polkavm::GLOBAL_CALLDATA_SIZE,
context.field_type(), context.word_type(),
AddressSpace::Stack, AddressSpace::Stack,
calldata_size_casted, calldata_size_casted,
); );
@@ -158,9 +179,9 @@ impl Entry {
); );
context.write_abi_pointer( context.write_abi_pointer(
calldata_end_pointer, calldata_end_pointer,
crate::eravm::GLOBAL_RETURN_DATA_POINTER, crate::polkavm::GLOBAL_RETURN_DATA_POINTER,
); );
context.write_abi_pointer(calldata_end_pointer, crate::eravm::GLOBAL_ACTIVE_POINTER); context.write_abi_pointer(calldata_end_pointer, crate::polkavm::GLOBAL_ACTIVE_POINTER);
Ok(()) Ok(())
} }
@@ -177,7 +198,7 @@ impl Entry {
.get_nth_param(Self::ARGUMENT_INDEX_CALL_FLAGS); .get_nth_param(Self::ARGUMENT_INDEX_CALL_FLAGS);
context.set_global( context.set_global(
crate::eravm::GLOBAL_CALL_FLAGS, crate::polkavm::GLOBAL_CALL_FLAGS,
is_deploy.get_type(), is_deploy.get_type(),
AddressSpace::Stack, AddressSpace::Stack,
is_deploy.into_int_value(), is_deploy.into_int_value(),
@@ -224,8 +245,9 @@ where
let entry_function_type = context.function_type(entry_arguments, 0, false); let entry_function_type = context.function_type(entry_arguments, 0, false);
context.add_function(Runtime::FUNCTION_ENTRY, entry_function_type, 0, None)?; context.add_function(Runtime::FUNCTION_ENTRY, entry_function_type, 0, None)?;
context.declare_extern_function("deploy")?; for symbol in runtime_api::EXPORTS {
context.declare_extern_function("call")?; context.declare_extern_function(symbol)?;
}
Ok(()) Ok(())
} }
@@ -239,14 +261,14 @@ where
.expect("the entry function should already be declared") .expect("the entry function should already be declared")
.borrow() .borrow()
.declaration; .declaration;
crate::EraVMFunction::set_attributes( crate::PolkaVMFunction::set_attributes(
context.llvm(), context.llvm(),
entry, entry,
vec![crate::EraVMAttribute::NoReturn], vec![crate::PolkaVMAttribute::NoReturn],
true, true,
); );
context.set_current_function("deploy")?; context.set_current_function(runtime_api::DEPLOY)?;
context.set_basic_block(context.current_function().borrow().entry_block()); context.set_basic_block(context.current_function().borrow().entry_block());
assert!(context assert!(context
@@ -256,7 +278,7 @@ where
context.set_basic_block(context.current_function().borrow().return_block); context.set_basic_block(context.current_function().borrow().return_block);
context.build_unreachable(); context.build_unreachable();
context.set_current_function("call")?; context.set_current_function(runtime_api::CALL)?;
context.set_basic_block(context.current_function().borrow().entry_block()); context.set_basic_block(context.current_function().borrow().entry_block());
assert!(context assert!(context
@@ -1,6 +1,4 @@
//!
//! The front-end runtime functions. //! The front-end runtime functions.
//!
pub mod default_call; pub mod default_call;
pub mod deploy_code; pub mod deploy_code;
@@ -8,18 +6,16 @@ pub mod deployer_call;
pub mod entry; pub mod entry;
pub mod runtime_code; pub mod runtime_code;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::function::declaration::Declaration as FunctionDeclaration; use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
use crate::eravm::WriteLLVM; use crate::polkavm::WriteLLVM;
use self::default_call::DefaultCall; use self::default_call::DefaultCall;
use self::deployer_call::DeployerCall; use self::deployer_call::DeployerCall;
///
/// The front-end runtime functions. /// The front-end runtime functions.
///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Runtime { pub struct Runtime {
/// The address space where the calldata is allocated. /// The address space where the calldata is allocated.
@@ -37,16 +33,12 @@ impl Runtime {
/// The runtime code function name. /// The runtime code function name.
pub const FUNCTION_RUNTIME_CODE: &'static str = "__runtime"; pub const FUNCTION_RUNTIME_CODE: &'static str = "__runtime";
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(address_space: AddressSpace) -> Self { pub fn new(address_space: AddressSpace) -> Self {
Self { address_space } Self { address_space }
} }
///
/// Returns the corresponding runtime function. /// Returns the corresponding runtime function.
///
pub fn default_call<'ctx, D>( pub fn default_call<'ctx, D>(
context: &Context<'ctx, D>, context: &Context<'ctx, D>,
call_function: FunctionDeclaration<'ctx>, call_function: FunctionDeclaration<'ctx>,
@@ -61,9 +53,7 @@ impl Runtime {
.declaration() .declaration()
} }
///
/// Returns the corresponding runtime function. /// Returns the corresponding runtime function.
///
pub fn deployer_call<'ctx, D>(context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx> pub fn deployer_call<'ctx, D>(context: &Context<'ctx, D>) -> FunctionDeclaration<'ctx>
where where
D: Dependency + Clone, D: Dependency + Clone,
@@ -1,20 +1,15 @@
//!
//! The runtime code function. //! The runtime code function.
//!
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::eravm::context::code_type::CodeType; use crate::polkavm::context::code_type::CodeType;
use crate::eravm::context::function::runtime::Runtime; use crate::polkavm::context::function::runtime::Runtime;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
use crate::eravm::WriteLLVM; use crate::polkavm::WriteLLVM;
///
/// The runtime code function. /// The runtime code function.
///
/// Is a special function that is only used by the front-end generated code. /// Is a special function that is only used by the front-end generated code.
///
#[derive(Debug)] #[derive(Debug)]
pub struct RuntimeCode<B, D> pub struct RuntimeCode<B, D>
where where
@@ -32,9 +27,7 @@ where
B: WriteLLVM<D>, B: WriteLLVM<D>,
D: Dependency + Clone, D: Dependency + Clone,
{ {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(inner: B) -> Self { pub fn new(inner: B) -> Self {
Self { Self {
inner, inner,
@@ -1,14 +1,9 @@
//!
//! The LLVM function Vyper data. //! The LLVM function Vyper data.
//!
use std::collections::HashMap; use std::collections::HashMap;
///
/// The LLVM function Vyper data. /// The LLVM function Vyper data.
///
/// Describes some data that is only relevant to Vyper. /// Describes some data that is only relevant to Vyper.
///
#[derive(Debug)] #[derive(Debug)]
pub struct VyperData { pub struct VyperData {
/// The block-local variables. They are still allocated at the beginning of the function, /// The block-local variables. They are still allocated at the beginning of the function,
@@ -29,23 +24,17 @@ impl VyperData {
/// The label arguments hashmap default capacity. /// The label arguments hashmap default capacity.
const LABEL_ARGUMENTS_HASHMAP_INITIAL_CAPACITY: usize = 16; const LABEL_ARGUMENTS_HASHMAP_INITIAL_CAPACITY: usize = 16;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
///
/// Returns the list of a Vyper label arguments. /// Returns the list of a Vyper label arguments.
///
pub fn label_arguments(&self, label_name: &str) -> Option<Vec<String>> { pub fn label_arguments(&self, label_name: &str) -> Option<Vec<String>> {
self.label_arguments.get(label_name).cloned() self.label_arguments.get(label_name).cloned()
} }
///
/// Inserts arguments for the specified label. /// Inserts arguments for the specified label.
///
pub fn insert_label_arguments(&mut self, label_name: String, arguments: Vec<String>) { pub fn insert_label_arguments(&mut self, label_name: String, arguments: Vec<String>) {
self.label_arguments.insert(label_name, arguments); self.label_arguments.insert(label_name, arguments);
} }
@@ -1,16 +1,11 @@
//!
//! The LLVM function Yul data. //! The LLVM function Yul data.
//!
use std::collections::HashMap; use std::collections::HashMap;
use num::BigUint; use num::BigUint;
///
/// The LLVM function Yul data. /// The LLVM function Yul data.
///
/// Describes some data that is only relevant to Yul. /// Describes some data that is only relevant to Yul.
///
#[derive(Debug)] #[derive(Debug)]
pub struct YulData { pub struct YulData {
/// The constants saved to variables. Used for peculiar cases like call simulation. /// The constants saved to variables. Used for peculiar cases like call simulation.
@@ -30,23 +25,17 @@ impl YulData {
/// The constants hashmap default capacity. /// The constants hashmap default capacity.
const CONSTANTS_HASHMAP_INITIAL_CAPACITY: usize = 16; const CONSTANTS_HASHMAP_INITIAL_CAPACITY: usize = 16;
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
///
/// Returns a constant if it has been saved. /// Returns a constant if it has been saved.
///
pub fn get_constant(&self, name: &str) -> Option<BigUint> { pub fn get_constant(&self, name: &str) -> Option<BigUint> {
self.constants.get(name).cloned() self.constants.get(name).cloned()
} }
///
/// Saves a constant detected with the partial constant propagation. /// Saves a constant detected with the partial constant propagation.
///
pub fn insert_constant(&mut self, name: String, value: BigUint) { pub fn insert_constant(&mut self, name: String, value: BigUint) {
self.constants.insert(name, value); self.constants.insert(name, value);
} }
@@ -1,17 +1,13 @@
//!
//! The LLVM global value. //! The LLVM global value.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use inkwell::values::BasicValue; use inkwell::values::BasicValue;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::EraVMDependency; use crate::PolkaVMDependency;
///
/// The LLVM global value. /// The LLVM global value.
///
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Global<'ctx> { pub struct Global<'ctx> {
/// The global type. /// The global type.
@@ -21,9 +17,7 @@ pub struct Global<'ctx> {
} }
impl<'ctx> Global<'ctx> { impl<'ctx> Global<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new<D, T, V>( pub fn new<D, T, V>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
r#type: T, r#type: T,
@@ -32,7 +26,7 @@ impl<'ctx> Global<'ctx> {
name: &str, name: &str,
) -> Self ) -> Self
where where
D: EraVMDependency + Clone, D: PolkaVMDependency + Clone,
T: BasicType<'ctx>, T: BasicType<'ctx>,
V: BasicValue<'ctx>, V: BasicValue<'ctx>,
{ {
@@ -1,10 +1,6 @@
//!
//! The LLVM IR generator loop. //! The LLVM IR generator loop.
//!
///
/// The LLVM IR generator loop. /// The LLVM IR generator loop.
///
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Loop<'ctx> { pub struct Loop<'ctx> {
/// The loop current block. /// The loop current block.
@@ -16,9 +12,7 @@ pub struct Loop<'ctx> {
} }
impl<'ctx> Loop<'ctx> { impl<'ctx> Loop<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new( pub fn new(
body_block: inkwell::basic_block::BasicBlock<'ctx>, body_block: inkwell::basic_block::BasicBlock<'ctx>,
continue_block: inkwell::basic_block::BasicBlock<'ctx>, continue_block: inkwell::basic_block::BasicBlock<'ctx>,
@@ -1,17 +1,13 @@
//!
//! The LLVM pointer. //! The LLVM pointer.
//!
use inkwell::types::BasicType; use inkwell::types::BasicType;
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::global::Global; use crate::polkavm::context::global::Global;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// The LLVM pointer. /// The LLVM pointer.
///
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Pointer<'ctx> { pub struct Pointer<'ctx> {
/// The pointee type. /// The pointee type.
@@ -23,9 +19,7 @@ pub struct Pointer<'ctx> {
} }
impl<'ctx> Pointer<'ctx> { impl<'ctx> Pointer<'ctx> {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new<T>( pub fn new<T>(
r#type: T, r#type: T,
address_space: AddressSpace, address_space: AddressSpace,
@@ -41,9 +35,7 @@ impl<'ctx> Pointer<'ctx> {
} }
} }
///
/// Wraps a 256-bit primitive type pointer. /// Wraps a 256-bit primitive type pointer.
///
pub fn new_stack_field<D>( pub fn new_stack_field<D>(
context: &Context<'ctx, D>, context: &Context<'ctx, D>,
value: inkwell::values::PointerValue<'ctx>, value: inkwell::values::PointerValue<'ctx>,
@@ -52,15 +44,13 @@ impl<'ctx> Pointer<'ctx> {
D: Dependency + Clone, D: Dependency + Clone,
{ {
Self { Self {
r#type: context.field_type().as_basic_type_enum(), r#type: context.word_type().as_basic_type_enum(),
address_space: AddressSpace::Stack, address_space: AddressSpace::Stack,
value, value,
} }
} }
///
/// Creates a new pointer with the specified `offset`. /// Creates a new pointer with the specified `offset`.
///
pub fn new_with_offset<D, T>( pub fn new_with_offset<D, T>(
context: &Context<'ctx, D>, context: &Context<'ctx, D>,
address_space: AddressSpace, address_space: AddressSpace,
@@ -78,7 +68,7 @@ impl<'ctx> Pointer<'ctx> {
"Stack pointers cannot be addressed" "Stack pointers cannot be addressed"
); );
let offset = context.safe_truncate_int_to_i32(offset).unwrap(); let offset = context.safe_truncate_int_to_xlen(offset).unwrap();
let value = context let value = context
.builder .builder
.build_int_to_ptr(offset, context.llvm().ptr_type(address_space.into()), name) .build_int_to_ptr(offset, context.llvm().ptr_type(address_space.into()), name)
@@ -86,9 +76,7 @@ impl<'ctx> Pointer<'ctx> {
Self::new(r#type, address_space, value) Self::new(r#type, address_space, value)
} }
///
/// Casts the pointer into another type. /// Casts the pointer into another type.
///
pub fn cast<T>(self, r#type: T) -> Self pub fn cast<T>(self, r#type: T) -> Self
where where
T: BasicType<'ctx>, T: BasicType<'ctx>,
@@ -100,6 +88,17 @@ impl<'ctx> Pointer<'ctx> {
} }
} }
/// Cast this pointer to a register sized integer value.
pub fn to_int<D>(&self, context: &Context<'ctx, D>) -> inkwell::values::IntValue<'ctx>
where
D: Dependency + Clone,
{
context
.builder()
.build_ptr_to_int(self.value, context.xlen_type(), "ptr_to_xlen")
.expect("we should be positioned")
}
pub fn address_space_cast<D>( pub fn address_space_cast<D>(
self, self,
context: &Context<'ctx, D>, context: &Context<'ctx, D>,
@@ -1,14 +1,9 @@
//!
//! The LLVM IR generator Solidity data. //! The LLVM IR generator Solidity data.
//!
use std::collections::BTreeMap; use std::collections::BTreeMap;
///
/// The LLVM IR generator Solidity data. /// The LLVM IR generator Solidity data.
///
/// Describes some data that is only relevant to Solidity. /// Describes some data that is only relevant to Solidity.
///
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SolidityData { pub struct SolidityData {
/// The immutables identifier-to-offset mapping. Is only used by Solidity due to /// The immutables identifier-to-offset mapping. Is only used by Solidity due to
@@ -17,39 +12,29 @@ pub struct SolidityData {
} }
impl SolidityData { impl SolidityData {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
///
/// Returns the current number of immutables values in the contract. /// Returns the current number of immutables values in the contract.
///
pub fn immutables_size(&self) -> usize { pub fn immutables_size(&self) -> usize {
self.immutables.len() * revive_common::BYTE_LENGTH_FIELD self.immutables.len() * revive_common::BYTE_LENGTH_WORD
} }
///
/// Allocates memory for an immutable value in the auxiliary heap. /// Allocates memory for an immutable value in the auxiliary heap.
///
/// If the identifier is already known, just returns its offset. /// If the identifier is already known, just returns its offset.
///
pub fn allocate_immutable(&mut self, identifier: &str) -> usize { pub fn allocate_immutable(&mut self, identifier: &str) -> usize {
let number_of_elements = self.immutables.len(); let number_of_elements = self.immutables.len();
let new_offset = number_of_elements * revive_common::BYTE_LENGTH_FIELD; let new_offset = number_of_elements * revive_common::BYTE_LENGTH_WORD;
*self *self
.immutables .immutables
.entry(identifier.to_owned()) .entry(identifier.to_owned())
.or_insert(new_offset) .or_insert(new_offset)
} }
///
/// Gets the offset of the immutable value. /// Gets the offset of the immutable value.
///
/// If the value is not yet allocated, then it is done forcibly. /// If the value is not yet allocated, then it is done forcibly.
///
pub fn get_or_allocate_immutable(&mut self, identifier: &str) -> usize { pub fn get_or_allocate_immutable(&mut self, identifier: &str) -> usize {
match self.immutables.get(identifier).copied() { match self.immutables.get(identifier).copied() {
Some(offset) => offset, Some(offset) => offset,
@@ -1,18 +1,16 @@
//!
//! The LLVM IR generator context tests. //! The LLVM IR generator context tests.
//!
use crate::eravm::context::attribute::Attribute;
use crate::eravm::context::Context;
use crate::eravm::DummyDependency;
use crate::optimizer::settings::Settings as OptimizerSettings; use crate::optimizer::settings::Settings as OptimizerSettings;
use crate::optimizer::Optimizer; use crate::optimizer::Optimizer;
use crate::polkavm::context::attribute::Attribute;
use crate::polkavm::context::Context;
use crate::polkavm::DummyDependency;
pub fn create_context( pub fn create_context(
llvm: &inkwell::context::Context, llvm: &inkwell::context::Context,
optimizer_settings: OptimizerSettings, optimizer_settings: OptimizerSettings,
) -> Context<DummyDependency> { ) -> Context<DummyDependency> {
crate::eravm::initialize_target(); crate::polkavm::initialize_target();
let module = llvm.create_module("test"); let module = llvm.create_module("test");
let optimizer = Optimizer::new(optimizer_settings); let optimizer = Optimizer::new(optimizer_settings);
@@ -29,13 +27,13 @@ pub fn check_attribute_null_pointer_is_invalid() {
.add_function( .add_function(
"test", "test",
context context
.field_type() .word_type()
.fn_type(&[context.field_type().into()], false), .fn_type(&[context.word_type().into()], false),
1, 1,
Some(inkwell::module::Linkage::External), Some(inkwell::module::Linkage::External),
) )
.expect("Failed to add function"); .expect("Failed to add function");
assert!(function assert!(!function
.borrow() .borrow()
.declaration() .declaration()
.value .value
@@ -52,8 +50,8 @@ pub fn check_attribute_optimize_for_size_mode_3() {
.add_function( .add_function(
"test", "test",
context context
.field_type() .word_type()
.fn_type(&[context.field_type().into()], false), .fn_type(&[context.word_type().into()], false),
1, 1,
Some(inkwell::module::Linkage::External), Some(inkwell::module::Linkage::External),
) )
@@ -75,8 +73,8 @@ pub fn check_attribute_optimize_for_size_mode_z() {
.add_function( .add_function(
"test", "test",
context context
.field_type() .word_type()
.fn_type(&[context.field_type().into()], false), .fn_type(&[context.word_type().into()], false),
1, 1,
Some(inkwell::module::Linkage::External), Some(inkwell::module::Linkage::External),
) )
@@ -98,8 +96,8 @@ pub fn check_attribute_min_size_mode_3() {
.add_function( .add_function(
"test", "test",
context context
.field_type() .word_type()
.fn_type(&[context.field_type().into()], false), .fn_type(&[context.word_type().into()], false),
1, 1,
Some(inkwell::module::Linkage::External), Some(inkwell::module::Linkage::External),
) )
@@ -121,8 +119,8 @@ pub fn check_attribute_min_size_mode_z() {
.add_function( .add_function(
"test", "test",
context context
.field_type() .word_type()
.fn_type(&[context.field_type().into()], false), .fn_type(&[context.word_type().into()], false),
1, 1,
Some(inkwell::module::Linkage::External), Some(inkwell::module::Linkage::External),
) )
@@ -1,12 +1,7 @@
//!
//! The LLVM IR generator Vyper data. //! The LLVM IR generator Vyper data.
//!
///
/// The LLVM IR generator Vyper data. /// The LLVM IR generator Vyper data.
///
/// Describes some data that is only relevant to Vyper. /// Describes some data that is only relevant to Vyper.
///
#[derive(Debug)] #[derive(Debug)]
pub struct VyperData { pub struct VyperData {
/// The immutables size tracker. Stores the size in bytes. /// The immutables size tracker. Stores the size in bytes.
@@ -17,9 +12,7 @@ pub struct VyperData {
} }
impl VyperData { impl VyperData {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(immutables_size: usize, is_forwarder_used: bool) -> Self { pub fn new(immutables_size: usize, is_forwarder_used: bool) -> Self {
Self { Self {
immutables_size, immutables_size,
@@ -27,23 +20,17 @@ impl VyperData {
} }
} }
///
/// Returns the size of the immutables data of the contract. /// Returns the size of the immutables data of the contract.
///
pub fn immutables_size(&self) -> usize { pub fn immutables_size(&self) -> usize {
self.immutables_size self.immutables_size
} }
///
/// Sets the forwarder usage flag. /// Sets the forwarder usage flag.
///
pub fn set_is_forwarder_used(&mut self) { pub fn set_is_forwarder_used(&mut self) {
self.is_forwarder_used = true; self.is_forwarder_used = true;
} }
///
/// Returns the forwarder usage flag. /// Returns the forwarder usage flag.
///
pub fn is_forwarder_used(&self) -> bool { pub fn is_forwarder_used(&self) -> bool {
self.is_forwarder_used self.is_forwarder_used
} }
@@ -1,16 +1,11 @@
//!
//! The LLVM IR generator Yul data. //! The LLVM IR generator Yul data.
//!
use std::collections::BTreeMap; use std::collections::BTreeMap;
use num::Zero; use num::Zero;
///
/// The LLVM IR generator Yul data. /// The LLVM IR generator Yul data.
///
/// Describes some data that is only relevant to Yul. /// Describes some data that is only relevant to Yul.
///
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct YulData { pub struct YulData {
/// The system mode flag. /// The system mode flag.
@@ -22,9 +17,7 @@ pub struct YulData {
} }
impl YulData { impl YulData {
///
/// A shortcut constructor. /// A shortcut constructor.
///
pub fn new(is_system_mode: bool) -> Self { pub fn new(is_system_mode: bool) -> Self {
Self { Self {
is_system_mode, is_system_mode,
@@ -32,16 +25,12 @@ impl YulData {
} }
} }
///
/// Whether the system mode is enabled. /// Whether the system mode is enabled.
///
pub fn is_system_mode(&self) -> bool { pub fn is_system_mode(&self) -> bool {
self.is_system_mode self.is_system_mode
} }
///
/// Declares a temporary constant array representation. /// Declares a temporary constant array representation.
///
pub fn const_array_declare(&mut self, index: u8, size: u16) -> anyhow::Result<()> { pub fn const_array_declare(&mut self, index: u8, size: u16) -> anyhow::Result<()> {
if self.const_arrays.contains_key(&index) { if self.const_arrays.contains_key(&index) {
anyhow::bail!( anyhow::bail!(
@@ -56,9 +45,7 @@ impl YulData {
Ok(()) Ok(())
} }
///
/// Sets a value in the constant array representation. /// Sets a value in the constant array representation.
///
pub fn const_array_set( pub fn const_array_set(
&mut self, &mut self,
index: u8, index: u8,
@@ -81,9 +68,7 @@ impl YulData {
Ok(()) Ok(())
} }
///
/// Finalizes the constant array declaration. /// Finalizes the constant array declaration.
///
pub fn const_array_take(&mut self, index: u8) -> anyhow::Result<Vec<num::BigUint>> { pub fn const_array_take(&mut self, index: u8) -> anyhow::Result<Vec<num::BigUint>> {
self.const_arrays.remove(&index).ok_or_else(|| { self.const_arrays.remove(&index).ok_or_else(|| {
anyhow::anyhow!("The constant array with index {} is not declared", index) anyhow::anyhow!("The constant array with index {} is not declared", index)
@@ -0,0 +1,205 @@
//! Translates the arithmetic operations.
use inkwell::values::BasicValue;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
/// Translates the arithmetic addition.
pub fn addition<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_add(operand_1, operand_2, "addition_result")?
.as_basic_value_enum())
}
/// Translates the arithmetic subtraction.
pub fn subtraction<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_sub(operand_1, operand_2, "subtraction_result")?
.as_basic_value_enum())
}
/// Translates the arithmetic multiplication.
pub fn multiplication<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context
.builder()
.build_int_mul(operand_1, operand_2, "multiplication_result")?
.as_basic_value_enum())
}
/// Translates the arithmetic division.
pub fn division<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
wrapped_division(context, operand_2, || {
Ok(context
.builder()
.build_int_unsigned_div(operand_1, operand_2, "DIV")?)
})
}
/// Translates the arithmetic remainder.
pub fn remainder<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
wrapped_division(context, operand_2, || {
Ok(context
.builder()
.build_int_unsigned_rem(operand_1, operand_2, "MOD")?)
})
}
/// Translates the signed arithmetic division.
/// Two differences between the EVM and LLVM IR:
/// 1. In case of division by zero, 0 is returned.
/// 2. In case of overflow, the first argument is returned.
pub fn division_signed<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
assert_eq!(
operand_2.get_type().get_bit_width(),
revive_common::BIT_LENGTH_WORD as u32
);
let block_calculate = context.append_basic_block("calculate");
let block_overflow = context.append_basic_block("overflow");
let block_select = context.append_basic_block("select_result");
let block_origin = context.basic_block();
context.builder().build_switch(
operand_2,
block_calculate,
&[
(context.word_type().const_zero(), block_select),
(context.word_type().const_all_ones(), block_overflow),
],
)?;
context.set_basic_block(block_calculate);
let quotient = context
.builder()
.build_int_signed_div(operand_1, operand_2, "SDIV")?;
context.build_unconditional_branch(block_select);
context.set_basic_block(block_overflow);
let max_uint = context.builder().build_int_z_extend(
context
.integer_type(revive_common::BIT_LENGTH_WORD - 1)
.const_all_ones(),
context.word_type(),
"max_uint",
)?;
let is_operand_1_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::EQ,
operand_1,
context.builder().build_int_neg(max_uint, "min_uint")?,
"is_operand_1_overflow",
)?;
context.build_conditional_branch(is_operand_1_overflow, block_select, block_calculate)?;
context.set_basic_block(block_select);
let result = context.builder().build_phi(context.word_type(), "result")?;
result.add_incoming(&[
(&operand_1, block_overflow),
(&context.word_const(0), block_origin),
(&quotient.as_basic_value_enum(), block_calculate),
]);
Ok(result.as_basic_value())
}
/// Translates the signed arithmetic remainder.
pub fn remainder_signed<'ctx, D>(
context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>,
operand_2: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
wrapped_division(context, operand_2, || {
Ok(context
.builder()
.build_int_signed_rem(operand_1, operand_2, "SMOD")?)
})
}
/// Wrap division operations so that zero will be returned if the
/// denominator is zero (see also Ethereum YP Appendix H.2).
///
/// The closure is expected to calculate and return the quotient.
///
/// The result is either the calculated quotient or zero,
/// selected at runtime.
fn wrapped_division<'ctx, D, F, T>(
context: &Context<'ctx, D>,
denominator: inkwell::values::IntValue<'ctx>,
f: F,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
F: FnOnce() -> anyhow::Result<T>,
T: inkwell::values::IntMathValue<'ctx>,
{
assert_eq!(
denominator.get_type().get_bit_width(),
revive_common::BIT_LENGTH_WORD as u32
);
let block_calculate = context.append_basic_block("calculate");
let block_select = context.append_basic_block("select");
let block_origin = context.basic_block();
context.builder().build_switch(
denominator,
block_calculate,
&[(context.word_const(0), block_select)],
)?;
context.set_basic_block(block_calculate);
let calculated_value = f()?.as_basic_value_enum();
context.build_unconditional_branch(block_select);
context.set_basic_block(block_select);
let result = context.builder().build_phi(context.word_type(), "result")?;
result.add_incoming(&[
(&context.word_const(0), block_origin),
(&calculated_value, block_calculate),
]);
Ok(result.as_basic_value())
}
@@ -1,15 +1,11 @@
//!
//! Translates the bitwise operations. //! Translates the bitwise operations.
//!
use inkwell::values::BasicValue; use inkwell::values::BasicValue;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// Translates the bitwise OR. /// Translates the bitwise OR.
///
pub fn or<'ctx, D>( pub fn or<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>, operand_1: inkwell::values::IntValue<'ctx>,
@@ -24,9 +20,7 @@ where
.as_basic_value_enum()) .as_basic_value_enum())
} }
///
/// Translates the bitwise XOR. /// Translates the bitwise XOR.
///
pub fn xor<'ctx, D>( pub fn xor<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>, operand_1: inkwell::values::IntValue<'ctx>,
@@ -41,9 +35,7 @@ where
.as_basic_value_enum()) .as_basic_value_enum())
} }
///
/// Translates the bitwise AND. /// Translates the bitwise AND.
///
pub fn and<'ctx, D>( pub fn and<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>, operand_1: inkwell::values::IntValue<'ctx>,
@@ -58,9 +50,7 @@ where
.as_basic_value_enum()) .as_basic_value_enum())
} }
///
/// Translates the bitwise shift left. /// Translates the bitwise shift left.
///
pub fn shift_left<'ctx, D>( pub fn shift_left<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
shift: inkwell::values::IntValue<'ctx>, shift: inkwell::values::IntValue<'ctx>,
@@ -73,17 +63,17 @@ where
let non_overflow_block = context.append_basic_block("shift_left_non_overflow"); let non_overflow_block = context.append_basic_block("shift_left_non_overflow");
let join_block = context.append_basic_block("shift_left_join"); let join_block = context.append_basic_block("shift_left_join");
let result_pointer = context.build_alloca(context.field_type(), "shift_left_result_pointer"); let result_pointer = context.build_alloca(context.word_type(), "shift_left_result_pointer");
let condition_is_overflow = context.builder().build_int_compare( let condition_is_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::UGT, inkwell::IntPredicate::UGT,
shift, shift,
context.field_const((revive_common::BIT_LENGTH_FIELD - 1) as u64), context.word_const((revive_common::BIT_LENGTH_WORD - 1) as u64),
"shift_left_is_overflow", "shift_left_is_overflow",
)?; )?;
context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?; context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?;
context.set_basic_block(overflow_block); context.set_basic_block(overflow_block);
context.build_store(result_pointer, context.field_const(0))?; context.build_store(result_pointer, context.word_const(0))?;
context.build_unconditional_branch(join_block); context.build_unconditional_branch(join_block);
context.set_basic_block(non_overflow_block); context.set_basic_block(non_overflow_block);
@@ -98,9 +88,7 @@ where
context.build_load(result_pointer, "shift_left_result") context.build_load(result_pointer, "shift_left_result")
} }
///
/// Translates the bitwise shift right. /// Translates the bitwise shift right.
///
pub fn shift_right<'ctx, D>( pub fn shift_right<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
shift: inkwell::values::IntValue<'ctx>, shift: inkwell::values::IntValue<'ctx>,
@@ -113,17 +101,17 @@ where
let non_overflow_block = context.append_basic_block("shift_right_non_overflow"); let non_overflow_block = context.append_basic_block("shift_right_non_overflow");
let join_block = context.append_basic_block("shift_right_join"); let join_block = context.append_basic_block("shift_right_join");
let result_pointer = context.build_alloca(context.field_type(), "shift_right_result_pointer"); let result_pointer = context.build_alloca(context.word_type(), "shift_right_result_pointer");
let condition_is_overflow = context.builder().build_int_compare( let condition_is_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::UGT, inkwell::IntPredicate::UGT,
shift, shift,
context.field_const((revive_common::BIT_LENGTH_FIELD - 1) as u64), context.word_const((revive_common::BIT_LENGTH_WORD - 1) as u64),
"shift_right_is_overflow", "shift_right_is_overflow",
)?; )?;
context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?; context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?;
context.set_basic_block(overflow_block); context.set_basic_block(overflow_block);
context.build_store(result_pointer, context.field_const(0))?; context.build_store(result_pointer, context.word_const(0))?;
context.build_unconditional_branch(join_block); context.build_unconditional_branch(join_block);
context.set_basic_block(non_overflow_block); context.set_basic_block(non_overflow_block);
@@ -140,9 +128,7 @@ where
context.build_load(result_pointer, "shift_right_result") context.build_load(result_pointer, "shift_right_result")
} }
///
/// Translates the arithmetic bitwise shift right. /// Translates the arithmetic bitwise shift right.
///
pub fn shift_right_arithmetic<'ctx, D>( pub fn shift_right_arithmetic<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
shift: inkwell::values::IntValue<'ctx>, shift: inkwell::values::IntValue<'ctx>,
@@ -159,14 +145,12 @@ where
let non_overflow_block = context.append_basic_block("shift_right_arithmetic_non_overflow"); let non_overflow_block = context.append_basic_block("shift_right_arithmetic_non_overflow");
let join_block = context.append_basic_block("shift_right_arithmetic_join"); let join_block = context.append_basic_block("shift_right_arithmetic_join");
let result_pointer = context.build_alloca( let result_pointer =
context.field_type(), context.build_alloca(context.word_type(), "shift_right_arithmetic_result_pointer");
"shift_right_arithmetic_result_pointer",
);
let condition_is_overflow = context.builder().build_int_compare( let condition_is_overflow = context.builder().build_int_compare(
inkwell::IntPredicate::UGT, inkwell::IntPredicate::UGT,
shift, shift,
context.field_const((revive_common::BIT_LENGTH_FIELD - 1) as u64), context.word_const((revive_common::BIT_LENGTH_WORD - 1) as u64),
"shift_right_arithmetic_is_overflow", "shift_right_arithmetic_is_overflow",
)?; )?;
context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?; context.build_conditional_branch(condition_is_overflow, overflow_block, non_overflow_block)?;
@@ -174,7 +158,7 @@ where
context.set_basic_block(overflow_block); context.set_basic_block(overflow_block);
let sign_bit = context.builder().build_right_shift( let sign_bit = context.builder().build_right_shift(
value, value,
context.field_const((revive_common::BIT_LENGTH_FIELD - 1) as u64), context.word_const((revive_common::BIT_LENGTH_WORD - 1) as u64),
false, false,
"shift_right_arithmetic_sign_bit", "shift_right_arithmetic_sign_bit",
)?; )?;
@@ -190,11 +174,11 @@ where
)?; )?;
context.set_basic_block(overflow_positive_block); context.set_basic_block(overflow_positive_block);
context.build_store(result_pointer, context.field_const(0))?; context.build_store(result_pointer, context.word_const(0))?;
context.build_unconditional_branch(join_block); context.build_unconditional_branch(join_block);
context.set_basic_block(overflow_negative_block); context.set_basic_block(overflow_negative_block);
context.build_store(result_pointer, context.field_type().const_all_ones())?; context.build_store(result_pointer, context.word_type().const_all_ones())?;
context.build_unconditional_branch(join_block); context.build_unconditional_branch(join_block);
context.set_basic_block(non_overflow_block); context.set_basic_block(non_overflow_block);
@@ -211,9 +195,7 @@ where
context.build_load(result_pointer, "shift_right_arithmetic_result") context.build_load(result_pointer, "shift_right_arithmetic_result")
} }
///
/// Translates the `byte` instruction. /// Translates the `byte` instruction.
///
pub fn byte<'ctx, D>( pub fn byte<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>, operand_1: inkwell::values::IntValue<'ctx>,
@@ -1,20 +1,15 @@
//!
//! Translates a contract call. //! Translates a contract call.
//!
use inkwell::values::BasicValue; use inkwell::values::BasicValue;
use crate::eravm::context::argument::Argument; use crate::polkavm::context::argument::Argument;
use crate::eravm::context::function::declaration::Declaration as FunctionDeclaration; use crate::polkavm::context::function::declaration::Declaration as FunctionDeclaration;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// Translates a contract call. /// Translates a contract call.
///
/// If the `simulation_address` is specified, the call is substituted with another instruction /// If the `simulation_address` is specified, the call is substituted with another instruction
/// according to the specification. /// according to the specification.
///
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn default<'ctx, D>( pub fn default<'ctx, D>(
_context: &mut Context<'ctx, D>, _context: &mut Context<'ctx, D>,
@@ -95,9 +90,7 @@ where
*/ */
} }
///
/// Translates the Yul `linkersymbol` instruction. /// Translates the Yul `linkersymbol` instruction.
///
pub fn linker_symbol<'ctx, D>( pub fn linker_symbol<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
mut arguments: [Argument<'ctx>; 1], mut arguments: [Argument<'ctx>; 1],
@@ -1,16 +1,12 @@
//!
//! Translates the calldata instructions. //! Translates the calldata instructions.
//!
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::pointer::Pointer; use crate::polkavm::context::pointer::Pointer;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
use inkwell::types::BasicType; use inkwell::types::BasicType;
///
/// Translates the calldata load. /// Translates the calldata load.
///
pub fn load<'ctx, D>( pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>, offset: inkwell::values::IntValue<'ctx>,
@@ -19,13 +15,13 @@ where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let calldata_pointer = context let calldata_pointer = context
.get_global(crate::eravm::GLOBAL_CALLDATA_POINTER)? .get_global(crate::polkavm::GLOBAL_CALLDATA_POINTER)?
.value .value
.as_pointer_value(); .as_pointer_value();
let offset = context.build_gep( let offset = context.build_gep(
Pointer::new(context.byte_type(), AddressSpace::Stack, calldata_pointer), Pointer::new(context.byte_type(), AddressSpace::Stack, calldata_pointer),
&[offset], &[offset],
context.field_type().as_basic_type_enum(), context.word_type().as_basic_type_enum(),
"calldata_pointer_with_offset", "calldata_pointer_with_offset",
); );
context context
@@ -33,23 +29,19 @@ where
.and_then(|value| context.build_byte_swap(value)) .and_then(|value| context.build_byte_swap(value))
} }
///
/// Translates the calldata size. /// Translates the calldata size.
///
pub fn size<'ctx, D>( pub fn size<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> ) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let value = context.get_global_value(crate::eravm::GLOBAL_CALLDATA_SIZE)?; let value = context.get_global_value(crate::polkavm::GLOBAL_CALLDATA_SIZE)?;
Ok(value) Ok(value)
} }
///
/// Translates the calldata copy. /// Translates the calldata copy.
///
pub fn copy<'ctx, D>( pub fn copy<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
destination_offset: inkwell::values::IntValue<'ctx>, destination_offset: inkwell::values::IntValue<'ctx>,
@@ -59,17 +51,17 @@ pub fn copy<'ctx, D>(
where where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let offset = context.safe_truncate_int_to_i32(destination_offset)?; let offset = context.safe_truncate_int_to_xlen(destination_offset)?;
let size = context.safe_truncate_int_to_i32(size)?; let size = context.safe_truncate_int_to_xlen(size)?;
let destination = context.build_heap_gep(offset, size)?; let destination = context.build_heap_gep(offset, size)?;
let calldata_pointer = context let calldata_pointer = context
.get_global(crate::eravm::GLOBAL_CALLDATA_POINTER)? .get_global(crate::polkavm::GLOBAL_CALLDATA_POINTER)?
.value .value
.as_pointer_value(); .as_pointer_value();
let source = context.build_gep( let source = context.build_gep(
Pointer::new(context.byte_type(), AddressSpace::Stack, calldata_pointer), Pointer::new(context.byte_type(), AddressSpace::Stack, calldata_pointer),
&[context.safe_truncate_int_to_i32(source_offset)?], &[context.safe_truncate_int_to_xlen(source_offset)?],
context.byte_type(), context.byte_type(),
"calldata_pointer_with_offset", "calldata_pointer_with_offset",
); );
@@ -1,17 +1,12 @@
//!
//! Translates the comparison operations. //! Translates the comparison operations.
//!
use inkwell::values::BasicValue; use inkwell::values::BasicValue;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// Translates the comparison operations. /// Translates the comparison operations.
///
/// There is not difference between the EVM and LLVM IR behaviors. /// There is not difference between the EVM and LLVM IR behaviors.
///
pub fn compare<'ctx, D>( pub fn compare<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
operand_1: inkwell::values::IntValue<'ctx>, operand_1: inkwell::values::IntValue<'ctx>,
@@ -29,7 +24,7 @@ where
)?; )?;
let result = context.builder().build_int_z_extend_or_bit_cast( let result = context.builder().build_int_z_extend_or_bit_cast(
result, result,
context.field_type(), context.word_type(),
"comparison_result_extended", "comparison_result_extended",
)?; )?;
Ok(result.as_basic_value_enum()) Ok(result.as_basic_value_enum())
@@ -0,0 +1,211 @@
//! Translates the context getter instructions.
use inkwell::values::BasicValue;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm_const::runtime_api;
/// Translates the `gas_limit` instruction.
pub fn gas_limit<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
/// Translates the `gas_price` instruction.
pub fn gas_price<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
/// Translates the `tx.origin` instruction.
pub fn origin<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
/// Translates the `chain_id` instruction.
pub fn chain_id<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
/// Translates the `block_number` instruction.
pub fn block_number<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let (output_pointer, output_length_pointer) = context.build_stack_parameter(
revive_common::BIT_LENGTH_BLOCK_NUMBER,
"block_timestamp_output",
);
context.build_runtime_call(
runtime_api::BLOCK_NUMBER,
&[
output_pointer.to_int(context).into(),
output_length_pointer.to_int(context).into(),
],
);
context.build_load_word(
output_pointer,
revive_common::BIT_LENGTH_BLOCK_NUMBER,
"block_number",
)
}
/// Translates the `block_timestamp` instruction.
pub fn block_timestamp<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let (output_pointer, output_length_pointer) = context.build_stack_parameter(
revive_common::BIT_LENGTH_BLOCK_TIMESTAMP,
"block_timestamp_output",
);
context.build_runtime_call(
runtime_api::NOW,
&[
output_pointer.to_int(context).into(),
output_length_pointer.to_int(context).into(),
],
);
context.build_load_word(
output_pointer,
revive_common::BIT_LENGTH_BLOCK_TIMESTAMP,
"block_timestamp",
)
}
/// Translates the `block_hash` instruction.
pub fn block_hash<'ctx, D>(
_context: &mut Context<'ctx, D>,
_index: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
/// Translates the `difficulty` instruction.
pub fn difficulty<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context.word_const(2500000000000000).as_basic_value_enum())
}
/// Translates the `coinbase` instruction.
pub fn coinbase<'ctx, D>(
_context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
/// Translates the `basefee` instruction.
pub fn basefee<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context.word_const(0).as_basic_value_enum())
}
/// Translates the `msize` instruction.
pub fn msize<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let heap_end = context.build_sbrk(context.xlen_type().const_zero())?;
let heap_start = context
.get_global(crate::polkavm::GLOBAL_HEAP_MEMORY_POINTER)?
.value
.as_pointer_value();
let heap_size = context.builder().build_int_nuw_sub(
context
.builder()
.build_ptr_to_int(heap_end, context.xlen_type(), "heap_end")?,
context
.builder()
.build_ptr_to_int(heap_start, context.xlen_type(), "heap_start")?,
"heap_size",
)?;
Ok(context
.builder()
.build_int_z_extend(heap_size, context.word_type(), "heap_size_extended")?
.as_basic_value_enum())
}
/// Translates the `address` instruction.
pub fn address<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let (output_pointer, output_length_pointer) =
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "address_output");
context.build_runtime_call(
runtime_api::ADDRESS,
&[
output_pointer.to_int(context).into(),
output_length_pointer.to_int(context).into(),
],
);
let value = context.build_byte_swap(context.build_load(output_pointer, "address")?)?;
Ok(context
.builder()
.build_int_z_extend(value.into_int_value(), context.word_type(), "address_zext")?
.into())
}
/// Translates the `caller` instruction.
pub fn caller<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let (output_pointer, output_length_pointer) =
context.build_stack_parameter(revive_common::BIT_LENGTH_ETH_ADDRESS, "caller_output");
context.build_runtime_call(
runtime_api::CALLER,
&[
output_pointer.to_int(context).into(),
output_length_pointer.to_int(context).into(),
],
);
let value = context.build_byte_swap(context.build_load(output_pointer, "caller")?)?;
Ok(context
.builder()
.build_int_z_extend(value.into_int_value(), context.word_type(), "caller_zext")?
.into())
}
@@ -1,21 +1,16 @@
//!
//! Translates the contract creation instructions. //! Translates the contract creation instructions.
//!
use inkwell::values::BasicValue; use inkwell::values::BasicValue;
use num::Zero; use num::Zero;
use crate::eravm::context::argument::Argument; use crate::polkavm::context::argument::Argument;
use crate::eravm::context::code_type::CodeType; use crate::polkavm::context::code_type::CodeType;
use crate::eravm::context::function::runtime::Runtime; use crate::polkavm::context::function::runtime::Runtime;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// Translates the contract `create` instruction. /// Translates the contract `create` instruction.
///
/// The instruction is simulated by a call to a system contract. /// The instruction is simulated by a call to a system contract.
///
pub fn create<'ctx, D>( pub fn create<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
value: inkwell::values::IntValue<'ctx>, value: inkwell::values::IntValue<'ctx>,
@@ -26,10 +21,10 @@ where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let signature_hash_string = let signature_hash_string =
crate::eravm::utils::keccak256(crate::eravm::DEPLOYER_SIGNATURE_CREATE.as_bytes()); crate::polkavm::utils::keccak256(crate::polkavm::DEPLOYER_SIGNATURE_CREATE.as_bytes());
let signature_hash = context.field_const_str_hex(signature_hash_string.as_str()); let signature_hash = context.word_const_str_hex(signature_hash_string.as_str());
let salt = context.field_const(0); let salt = context.word_const(0);
let function = Runtime::deployer_call(context); let function = Runtime::deployer_call(context);
let result = context let result = context
@@ -49,11 +44,8 @@ where
Ok(result) Ok(result)
} }
///
/// Translates the contract `create2` instruction. /// Translates the contract `create2` instruction.
///
/// The instruction is simulated by a call to a system contract. /// The instruction is simulated by a call to a system contract.
///
pub fn create2<'ctx, D>( pub fn create2<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
value: inkwell::values::IntValue<'ctx>, value: inkwell::values::IntValue<'ctx>,
@@ -65,10 +57,10 @@ where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let signature_hash_string = let signature_hash_string =
crate::eravm::utils::keccak256(crate::eravm::DEPLOYER_SIGNATURE_CREATE2.as_bytes()); crate::polkavm::utils::keccak256(crate::polkavm::DEPLOYER_SIGNATURE_CREATE2.as_bytes());
let signature_hash = context.field_const_str_hex(signature_hash_string.as_str()); let signature_hash = context.word_const_str_hex(signature_hash_string.as_str());
let salt = salt.unwrap_or_else(|| context.field_const(0)); let salt = salt.unwrap_or_else(|| context.word_const(0));
let function = Runtime::deployer_call(context); let function = Runtime::deployer_call(context);
let result = context let result = context
@@ -88,12 +80,9 @@ where
Ok(result) Ok(result)
} }
///
/// Translates the contract hash instruction, which is actually used to set the hash of the contract /// Translates the contract hash instruction, which is actually used to set the hash of the contract
/// being created, or other related auxiliary data. /// being created, or other related auxiliary data.
///
/// Represents `dataoffset` in Yul and `PUSH [$]` in the EVM legacy assembly. /// Represents `dataoffset` in Yul and `PUSH [$]` in the EVM legacy assembly.
///
pub fn contract_hash<'ctx, D>( pub fn contract_hash<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
identifier: String, identifier: String,
@@ -118,7 +107,7 @@ where
})?; })?;
if contract_path.as_str() == parent { if contract_path.as_str() == parent {
return Ok(Argument::new_with_constant( return Ok(Argument::new_with_constant(
context.field_const(0).as_basic_value_enum(), context.word_const(0).as_basic_value_enum(),
num::BigUint::zero(), num::BigUint::zero(),
)); ));
} else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime { } else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime {
@@ -127,25 +116,21 @@ where
let hash_string = context.compile_dependency(identifier.as_str())?; let hash_string = context.compile_dependency(identifier.as_str())?;
let hash_value = context let hash_value = context
.field_const_str_hex(hash_string.as_str()) .word_const_str_hex(hash_string.as_str())
.as_basic_value_enum(); .as_basic_value_enum();
Ok(Argument::new_with_original(hash_value, hash_string)) Ok(Argument::new_with_original(hash_value, hash_string))
} }
///
/// Translates the deployer call header size instruction, Usually, the header consists of: /// Translates the deployer call header size instruction, Usually, the header consists of:
/// - the deployer contract method signature /// - the deployer contract method signature
/// - the salt if the call is `create2`, or zero if the call is `create1` /// - the salt if the call is `create2`, or zero if the call is `create1`
/// - the hash of the bytecode of the contract whose instance is being created /// - the hash of the bytecode of the contract whose instance is being created
/// - the offset of the constructor arguments /// - the offset of the constructor arguments
/// - the length of the constructor arguments /// - the length of the constructor arguments
///
/// If the call is `create1`, the space for the salt is still allocated, because the memory for the /// If the call is `create1`, the space for the salt is still allocated, because the memory for the
/// header is allocated by the Yul or EVM legacy assembly before it is known which version of /// header is allocated by the Yul or EVM legacy assembly before it is known which version of
/// `create` is going to be used. /// `create` is going to be used.
///
/// Represents `datasize` in Yul and `PUSH #[$]` in the EVM legacy assembly. /// Represents `datasize` in Yul and `PUSH #[$]` in the EVM legacy assembly.
///
pub fn header_size<'ctx, D>( pub fn header_size<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
identifier: String, identifier: String,
@@ -170,16 +155,16 @@ where
})?; })?;
if contract_path.as_str() == parent { if contract_path.as_str() == parent {
return Ok(Argument::new_with_constant( return Ok(Argument::new_with_constant(
context.field_const(0).as_basic_value_enum(), context.word_const(0).as_basic_value_enum(),
num::BigUint::zero(), num::BigUint::zero(),
)); ));
} else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime { } else if identifier.ends_with("_deployed") && code_type == CodeType::Runtime {
anyhow::bail!("type({}).runtimeCode is not supported", identifier); anyhow::bail!("type({}).runtimeCode is not supported", identifier);
} }
let size_bigint = num::BigUint::from(crate::eravm::DEPLOYER_CALL_HEADER_SIZE); let size_bigint = num::BigUint::from(crate::polkavm::DEPLOYER_CALL_HEADER_SIZE);
let size_value = context let size_value = context
.field_const(crate::eravm::DEPLOYER_CALL_HEADER_SIZE as u64) .word_const(crate::polkavm::DEPLOYER_CALL_HEADER_SIZE as u64)
.as_basic_value_enum(); .as_basic_value_enum();
Ok(Argument::new_with_constant(size_value, size_bigint)) Ok(Argument::new_with_constant(size_value, size_bigint))
} }
@@ -0,0 +1,31 @@
//! Translates the cryptographic operations.
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm_const::runtime_api;
/// Translates the `sha3` instruction.
pub fn sha3<'ctx, D>(
context: &mut Context<'ctx, D>,
offset: inkwell::values::IntValue<'ctx>,
length: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let offset_casted = context.safe_truncate_int_to_xlen(offset)?;
let length_casted = context.safe_truncate_int_to_xlen(length)?;
let input_pointer = context.build_heap_gep(offset_casted, length_casted)?;
let output_pointer = context.build_alloca(context.word_type(), "output_pointer");
context.build_runtime_call(
runtime_api::HASH_KECCAK_256,
&[
input_pointer.to_int(context).into(),
length_casted.into(),
output_pointer.to_int(context).into(),
],
);
context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?)
}
@@ -0,0 +1,51 @@
//! Translates the value and balance operations.
use inkwell::values::BasicValue;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm_const::runtime_api;
/// Translates the `gas` instruction.
pub fn gas<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
Ok(context.integer_const(256, 0).as_basic_value_enum())
}
/// Translates the `value` instruction.
pub fn value<'ctx, D>(
context: &mut Context<'ctx, D>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
let (output_pointer, output_length_pointer) =
context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output");
context.build_runtime_call(
runtime_api::VALUE_TRANSFERRED,
&[
output_pointer.to_int(context).into(),
output_length_pointer.to_int(context).into(),
],
);
context.build_load_word(
output_pointer,
revive_common::BIT_LENGTH_VALUE,
"value_transferred",
)
}
/// Translates the `balance` instructions.
pub fn balance<'ctx, D>(
_context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where
D: Dependency + Clone,
{
todo!()
}
@@ -0,0 +1,133 @@
//! Translates a log or event call.
use inkwell::values::BasicValue;
use crate::polkavm::context::Context;
use crate::polkavm::Dependency;
use crate::polkavm_const::runtime_api;
/// Translates a log or event call.
pub fn log<'ctx, D>(
context: &mut Context<'ctx, D>,
input_offset: inkwell::values::IntValue<'ctx>,
input_length: inkwell::values::IntValue<'ctx>,
topics: Vec<inkwell::values::IntValue<'ctx>>,
) -> anyhow::Result<()>
where
D: Dependency + Clone,
{
let input_offset = context.safe_truncate_int_to_xlen(input_offset)?;
let input_length = context.safe_truncate_int_to_xlen(input_length)?;
let input_pointer = context.builder().build_ptr_to_int(
context.build_heap_gep(input_offset, input_length)?.value,
context.xlen_type(),
"event_input_offset",
)?;
if topics.is_empty() {
let _ = context.build_runtime_call(
runtime_api::DEPOSIT_EVENT,
&[
context.xlen_type().const_zero().as_basic_value_enum(),
context.xlen_type().const_zero().as_basic_value_enum(),
input_pointer.as_basic_value_enum(),
input_length.as_basic_value_enum(),
],
);
return Ok(());
}
let name = match topics.len() {
1 => "__log_1",
2 => "__log_2",
3 => "__log_3",
4 => "__log_4",
_ => unreachable!(),
};
let function = context.module().get_function(name).unwrap_or_else(|| {
let position = context.basic_block();
let mut parameters = vec![context.xlen_type().into(), context.xlen_type().into()];
parameters.extend_from_slice(
&topics
.iter()
.map(|_| context.word_type().into())
.collect::<Vec<_>>(),
);
let function = context.module().add_function(
name,
context.void_type().fn_type(&parameters, false),
None,
);
let block_entry = context.llvm().append_basic_block(function, "entry");
context.set_basic_block(block_entry);
let parameters = function.get_param_iter().collect::<Vec<_>>();
let topics = &parameters[2..];
let input_offset = parameters.first().unwrap();
let input_length = parameters.get(1).unwrap();
let topics_buffer_size = topics.len() * revive_common::BYTE_LENGTH_WORD;
let topics_buffer_pointer = context.build_alloca(
context.byte_type().array_type(topics_buffer_size as u32),
"topics_buffer",
);
for (n, topic) in topics.iter().enumerate() {
let topic_buffer_offset = context
.xlen_type()
.const_int((n * revive_common::BYTE_LENGTH_WORD) as u64, false);
context
.build_store(
context.build_gep(
topics_buffer_pointer,
&[context.xlen_type().const_zero(), topic_buffer_offset],
context.byte_type(),
"topic_buffer_gep",
),
context
.build_byte_swap(topic.as_basic_value_enum())
.unwrap(),
)
.unwrap();
}
let arguments = [
context
.builder()
.build_ptr_to_int(
topics_buffer_pointer.value,
context.xlen_type(),
"event_topics_offset",
)
.unwrap()
.as_basic_value_enum(),
context
.xlen_type()
.const_int(topics_buffer_size as u64, false)
.as_basic_value_enum(),
input_offset.as_basic_value_enum(),
input_length.as_basic_value_enum(),
];
let _ = context.build_runtime_call(runtime_api::DEPOSIT_EVENT, &arguments);
context.builder().build_return(None).unwrap();
context.set_basic_block(position);
function
});
let mut arguments = vec![
input_pointer.as_basic_value_enum().into(),
input_length.as_basic_value_enum().into(),
];
arguments.extend_from_slice(
&topics
.iter()
.map(|value| value.as_basic_value_enum().into())
.collect::<Vec<_>>(),
);
let _ = context
.builder()
.build_direct_call(function, &arguments[..], "call_log");
Ok(())
}
@@ -1,13 +1,9 @@
//!
//! Translates the external code operations. //! Translates the external code operations.
//!
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// Translates the `extcodesize` instruction. /// Translates the `extcodesize` instruction.
///
pub fn size<'ctx, D>( pub fn size<'ctx, D>(
_context: &mut Context<'ctx, D>, _context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>, _address: inkwell::values::IntValue<'ctx>,
@@ -18,9 +14,7 @@ where
todo!() todo!()
} }
///
/// Translates the `extcodehash` instruction. /// Translates the `extcodehash` instruction.
///
pub fn hash<'ctx, D>( pub fn hash<'ctx, D>(
_context: &mut Context<'ctx, D>, _context: &mut Context<'ctx, D>,
_address: inkwell::values::IntValue<'ctx>, _address: inkwell::values::IntValue<'ctx>,
@@ -1,19 +1,14 @@
//!
//! Translates the contract immutable operations. //! Translates the contract immutable operations.
//!
use crate::eravm::context::address_space::AddressSpace; use crate::polkavm::context::address_space::AddressSpace;
use crate::eravm::context::code_type::CodeType; use crate::polkavm::context::code_type::CodeType;
use crate::eravm::context::pointer::Pointer; use crate::polkavm::context::pointer::Pointer;
use crate::eravm::context::Context; use crate::polkavm::context::Context;
use crate::eravm::Dependency; use crate::polkavm::Dependency;
///
/// Translates the contract immutable load. /// Translates the contract immutable load.
///
/// In the deploy code the values are read from the auxiliary heap. /// In the deploy code the values are read from the auxiliary heap.
/// In the runtime code they are requested from the system contract. /// In the runtime code they are requested from the system contract.
///
pub fn load<'ctx, D>( pub fn load<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
index: inkwell::values::IntValue<'ctx>, index: inkwell::values::IntValue<'ctx>,
@@ -28,21 +23,21 @@ where
Some(CodeType::Deploy) => { Some(CodeType::Deploy) => {
let index_double = context.builder().build_int_mul( let index_double = context.builder().build_int_mul(
index, index,
context.field_const(2), context.word_const(2),
"immutable_load_index_double", "immutable_load_index_double",
)?; )?;
let offset_absolute = context.builder().build_int_add( let offset_absolute = context.builder().build_int_add(
index_double, index_double,
context.field_const( context.word_const(
crate::eravm::HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA crate::polkavm::HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA
+ (3 * revive_common::BYTE_LENGTH_FIELD) as u64, + (3 * revive_common::BYTE_LENGTH_WORD) as u64,
), ),
"immutable_offset_absolute", "immutable_offset_absolute",
)?; )?;
let immutable_pointer = Pointer::new_with_offset( let immutable_pointer = Pointer::new_with_offset(
context, context,
AddressSpace::HeapAuxiliary, AddressSpace::HeapAuxiliary,
context.field_type(), context.word_type(),
offset_absolute, offset_absolute,
"immutable_pointer", "immutable_pointer",
); );
@@ -54,14 +49,10 @@ where
} }
} }
///
/// Translates the contract immutable store. /// Translates the contract immutable store.
///
/// In the deploy code the values are written to the auxiliary heap at the predefined offset, /// In the deploy code the values are written to the auxiliary heap at the predefined offset,
/// being prepared for returning to the system contract for saving. /// being prepared for returning to the system contract for saving.
///
/// Ignored in the runtime code. /// Ignored in the runtime code.
///
pub fn store<'ctx, D>( pub fn store<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
index: inkwell::values::IntValue<'ctx>, index: inkwell::values::IntValue<'ctx>,
@@ -77,21 +68,21 @@ where
Some(CodeType::Deploy) => { Some(CodeType::Deploy) => {
let index_double = context.builder().build_int_mul( let index_double = context.builder().build_int_mul(
index, index,
context.field_const(2), context.word_const(2),
"immutable_load_index_double", "immutable_load_index_double",
)?; )?;
let index_offset_absolute = context.builder().build_int_add( let index_offset_absolute = context.builder().build_int_add(
index_double, index_double,
context.field_const( context.word_const(
crate::eravm::HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA crate::polkavm::HEAP_AUX_OFFSET_CONSTRUCTOR_RETURN_DATA
+ (2 * revive_common::BYTE_LENGTH_FIELD) as u64, + (2 * revive_common::BYTE_LENGTH_WORD) as u64,
), ),
"index_offset_absolute", "index_offset_absolute",
)?; )?;
let index_offset_pointer = Pointer::new_with_offset( let index_offset_pointer = Pointer::new_with_offset(
context, context,
AddressSpace::HeapAuxiliary, AddressSpace::HeapAuxiliary,
context.field_type(), context.word_type(),
index_offset_absolute, index_offset_absolute,
"immutable_index_pointer", "immutable_index_pointer",
); );
@@ -99,13 +90,13 @@ where
let value_offset_absolute = context.builder().build_int_add( let value_offset_absolute = context.builder().build_int_add(
index_offset_absolute, index_offset_absolute,
context.field_const(revive_common::BYTE_LENGTH_FIELD as u64), context.word_const(revive_common::BYTE_LENGTH_WORD as u64),
"value_offset_absolute", "value_offset_absolute",
)?; )?;
let value_offset_pointer = Pointer::new_with_offset( let value_offset_pointer = Pointer::new_with_offset(
context, context,
AddressSpace::HeapAuxiliary, AddressSpace::HeapAuxiliary,
context.field_type(), context.word_type(),
value_offset_absolute, value_offset_absolute,
"immutable_value_pointer", "immutable_value_pointer",
); );

Some files were not shown because too many files have changed in this diff Show More