From c14f5cce29bbfafd96f62d4d78f09c07363a5537 Mon Sep 17 00:00:00 2001 From: Garand Tyson Date: Thu, 7 Sep 2023 13:41:31 -0700 Subject: [PATCH] Fixed double count read fee bug and added tests --- Cargo.lock | 23 +- src/rust/Cargo.toml | 6 +- src/rust/src/host-dep-tree-curr.txt | 8 +- src/rust/src/host-dep-tree-prev.txt | 50 +- src/transactions/TransactionFrame.cpp | 8 +- .../test/InvokeHostFunctionTests.cpp | 483 +++++++++++++++++- 6 files changed, 493 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4550dbddb9..dce4f5d5cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -940,13 +940,13 @@ dependencies = [ [[package]] name = "soroban-env-common" version = "0.0.17" -source = "git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0#eb5a9ba053a7b64a8eff605db625525378f7bea0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" dependencies = [ "crate-git-revision", "ethnum", "num-derive", "num-traits", - "soroban-env-macros 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0)", + "soroban-env-macros 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64)", "soroban-wasmi", "static_assertions", "stellar-xdr", @@ -973,21 +973,17 @@ dependencies = [ "soroban-wasmi", "static_assertions", "stellar-strkey", - "tracy-client", ] [[package]] name = "soroban-env-host" version = "0.0.17" -source = "git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0#eb5a9ba053a7b64a8eff605db625525378f7bea0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" dependencies = [ "backtrace", - "curve25519-dalek", "ed25519-dalek", "getrandom", - "hex", "k256", - "log", "num-derive", "num-integer", "num-traits", @@ -995,11 +991,12 @@ dependencies = [ "rand_chacha", "sha2", "sha3", - "soroban-env-common 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0)", - "soroban-native-sdk-macros 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0)", + "soroban-env-common 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64)", + "soroban-native-sdk-macros 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64)", "soroban-wasmi", "static_assertions", "stellar-strkey", + "tracy-client", ] [[package]] @@ -1019,7 +1016,7 @@ dependencies = [ [[package]] name = "soroban-env-macros" version = "0.0.17" -source = "git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0#eb5a9ba053a7b64a8eff605db625525378f7bea0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" dependencies = [ "itertools", "proc-macro2", @@ -1044,7 +1041,7 @@ dependencies = [ [[package]] name = "soroban-native-sdk-macros" version = "0.0.17" -source = "git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0#eb5a9ba053a7b64a8eff605db625525378f7bea0" +source = "git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" dependencies = [ "itertools", "proc-macro2", @@ -1055,7 +1052,7 @@ dependencies = [ [[package]] name = "soroban-test-wasms" version = "0.0.17" -source = "git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537#3d6c35d1308fc36a05d30d257756e42fc928b537" +source = "git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" [[package]] name = "soroban-wasmi" @@ -1101,7 +1098,7 @@ dependencies = [ "log", "rustc-simple-version", "soroban-env-host 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537)", - "soroban-env-host 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=eb5a9ba053a7b64a8eff605db625525378f7bea0)", + "soroban-env-host 0.0.17 (git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64)", "soroban-test-wasms", "tracy-client", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index b2929eae1f..17790ae29b 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -28,7 +28,7 @@ rustc-simple-version = "0.1.0" version = "0.0.17" git = "https://github.com/stellar/rs-soroban-env" package = "soroban-env-host" -rev = "3d6c35d1308fc36a05d30d257756e42fc928b537" +rev = "f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" # This copy of the soroban host is _optional_ and only enabled during protocol # transitions. When transitioning from protocol N to N+1, the `curr` copy @@ -52,11 +52,11 @@ optional = true version = "0.0.17" git = "https://github.com/stellar/rs-soroban-env" package = "soroban-env-host" -rev = "eb5a9ba053a7b64a8eff605db625525378f7bea0" +rev = "3d6c35d1308fc36a05d30d257756e42fc928b537" [dependencies.soroban-test-wasms] git = "https://github.com/stellar/rs-soroban-env" -rev = "3d6c35d1308fc36a05d30d257756e42fc928b537" +rev = "f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64" [dependencies.cargo-lock] git = "https://github.com/rustsec/rustsec" diff --git a/src/rust/src/host-dep-tree-curr.txt b/src/rust/src/host-dep-tree-curr.txt index 5062de79e0..09adfe52ca 100644 --- a/src/rust/src/host-dep-tree-curr.txt +++ b/src/rust/src/host-dep-tree-curr.txt @@ -1,4 +1,4 @@ -soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537#3d6c35d1308fc36a05d30d257756e42fc928b537 +soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64 ├── tracy-client 0.15.2 checksum:434ecabbda9f67eeea1eab44d52f4a20538afa3e2c2770f2efc161142b25b608 │ ├── tracy-client-sys 0.20.0 checksum:e8cf8aeb20e40d13be65a0b134f8d82d360e72b2793a11de8867d7fbc0f9d6f6 │ │ └── cc 1.0.79 checksum:50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f @@ -86,13 +86,13 @@ soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35 │ ├── wasmi_arena 0.4.0 git+https://github.com/stellar/wasmi?rev=284c963ba080703061797e2a3cba0853edee0dd4#284c963ba080703061797e2a3cba0853edee0dd4 │ ├── spin 0.9.8 checksum:6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67 │ └── smallvec 1.10.0 checksum:a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0 -├── soroban-native-sdk-macros 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537#3d6c35d1308fc36a05d30d257756e42fc928b537 +├── soroban-native-sdk-macros 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64 │ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e │ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 │ ├── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 │ └── itertools 0.10.5 checksum:b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473 │ └── either 1.8.1 checksum:7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91 -├── soroban-env-common 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537#3d6c35d1308fc36a05d30d257756e42fc928b537 +├── soroban-env-common 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64 │ ├── stellar-xdr 0.0.17 git+https://github.com/stellar/rs-stellar-xdr?rev=39904e09941046dab61e6e35fc89e31bf2dea1cd#39904e09941046dab61e6e35fc89e31bf2dea1cd │ │ ├── hex 0.4.3 checksum:7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70 │ │ ├── crate-git-revision 0.0.6 checksum:c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98 @@ -109,7 +109,7 @@ soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35 │ │ └── base64 0.13.1 checksum:9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8 │ ├── static_assertions 1.1.0 checksum:a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f │ ├── soroban-wasmi 0.30.0-soroban git+https://github.com/stellar/wasmi?rev=284c963ba080703061797e2a3cba0853edee0dd4#284c963ba080703061797e2a3cba0853edee0dd4 -│ ├── soroban-env-macros 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537#3d6c35d1308fc36a05d30d257756e42fc928b537 +│ ├── soroban-env-macros 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64#f2f48d7b43da3b47f60e9f11dcb7ef5c67fa7e64 │ │ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e │ │ ├── stellar-xdr 0.0.17 git+https://github.com/stellar/rs-stellar-xdr?rev=39904e09941046dab61e6e35fc89e31bf2dea1cd#39904e09941046dab61e6e35fc89e31bf2dea1cd │ │ ├── serde_json 1.0.97 checksum:bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a diff --git a/src/rust/src/host-dep-tree-prev.txt b/src/rust/src/host-dep-tree-prev.txt index b4bf55d39a..fe55eb1d54 100644 --- a/src/rust/src/host-dep-tree-prev.txt +++ b/src/rust/src/host-dep-tree-prev.txt @@ -1,4 +1,4 @@ -soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0f42b4094481b7f32ecac825ce27c7114e0#f5c6c0f42b4094481b7f32ecac825ce27c7114e0 +soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=3d6c35d1308fc36a05d30d257756e42fc928b537#3d6c35d1308fc36a05d30d257756e42fc928b537 ├── stellar-strkey 0.0.7 git+https://github.com/stellar/rs-stellar-strkey?rev=e6ba45c60c16de28c7522586b80ed0150157df73#e6ba45c60c16de28c7522586b80ed0150157df73 │ ├── thiserror 1.0.40 checksum:978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac │ │ └── thiserror-impl 1.0.40 checksum:f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f @@ -24,44 +24,6 @@ soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0 │ ├── wasmi_arena 0.4.0 git+https://github.com/stellar/wasmi?rev=284c963ba080703061797e2a3cba0853edee0dd4#284c963ba080703061797e2a3cba0853edee0dd4 │ ├── spin 0.9.8 checksum:6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67 │ └── smallvec 1.10.0 checksum:a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0 -├── soroban-native-sdk-macros 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0f42b4094481b7f32ecac825ce27c7114e0#f5c6c0f42b4094481b7f32ecac825ce27c7114e0 -│ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e -│ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 -│ ├── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 -│ └── itertools 0.10.5 checksum:b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473 -│ └── either 1.8.1 checksum:7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91 -├── soroban-env-common 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0f42b4094481b7f32ecac825ce27c7114e0#f5c6c0f42b4094481b7f32ecac825ce27c7114e0 -│ ├── stellar-xdr 0.0.17 git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567#e2a9cbf72d94941de1bde6ba34a38e1f49328567 -│ │ ├── hex 0.4.3 checksum:7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70 -│ │ ├── crate-git-revision 0.0.6 checksum:c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98 -│ │ │ ├── serde_json 1.0.97 checksum:bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a -│ │ │ │ ├── serde 1.0.164 checksum:9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d -│ │ │ │ │ └── serde_derive 1.0.164 checksum:d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68 -│ │ │ │ │ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e -│ │ │ │ │ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 -│ │ │ │ │ └── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 -│ │ │ │ ├── ryu 1.0.13 checksum:f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041 -│ │ │ │ └── itoa 1.0.6 checksum:453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6 -│ │ │ ├── serde_derive 1.0.164 checksum:d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68 -│ │ │ └── serde 1.0.164 checksum:9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d -│ │ └── base64 0.13.1 checksum:9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8 -│ ├── static_assertions 1.1.0 checksum:a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f -│ ├── soroban-wasmi 0.30.0-soroban git+https://github.com/stellar/wasmi?rev=284c963ba080703061797e2a3cba0853edee0dd4#284c963ba080703061797e2a3cba0853edee0dd4 -│ ├── soroban-env-macros 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0f42b4094481b7f32ecac825ce27c7114e0#f5c6c0f42b4094481b7f32ecac825ce27c7114e0 -│ │ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e -│ │ ├── stellar-xdr 0.0.17 git+https://github.com/stellar/rs-stellar-xdr?rev=e2a9cbf72d94941de1bde6ba34a38e1f49328567#e2a9cbf72d94941de1bde6ba34a38e1f49328567 -│ │ ├── serde_json 1.0.97 checksum:bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a -│ │ ├── serde 1.0.164 checksum:9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d -│ │ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 -│ │ ├── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 -│ │ └── itertools 0.10.5 checksum:b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473 -│ ├── num-traits 0.2.15 checksum:578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd -│ ├── num-derive 0.4.0 checksum:9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e -│ │ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e -│ │ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 -│ │ └── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 -│ ├── ethnum 1.3.2 checksum:0198b9d0078e0f30dedc7acbb21c974e838fc8fae3ee170128658a98cb2c1c04 -│ └── crate-git-revision 0.0.6 checksum:c521bf1f43d31ed2f73441775ed31935d77901cb3451e44b38a1c1612fcbaf98 ├── sha3 0.10.8 checksum:75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60 │ ├── keccak 0.1.4 checksum:8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940 │ │ └── cpufeatures 0.2.8 checksum:03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c @@ -116,7 +78,9 @@ soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0 │ ├── num-traits 0.2.15 checksum:578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd │ └── autocfg 1.1.0 checksum:d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa ├── num-derive 0.4.0 checksum:9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e -├── log 0.4.19 checksum:b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4 +│ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e +│ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 +│ └── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 ├── k256 0.13.1 checksum:cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc │ ├── signature 2.1.0 checksum:5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500 │ │ ├── rand_core 0.6.4 checksum:ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c @@ -167,12 +131,15 @@ soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0 │ │ ├── digest 0.10.7 checksum:9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292 │ │ └── der 0.7.6 checksum:56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17 │ └── cfg-if 1.0.0 checksum:baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd -├── hex 0.4.3 checksum:7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70 ├── getrandom 0.2.10 checksum:be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427 ├── ed25519-dalek 2.0.0 checksum:7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980 │ ├── zeroize 1.6.0 checksum:2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9 │ ├── sha2 0.10.7 checksum:479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8 │ ├── serde 1.0.164 checksum:9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d +│ │ └── serde_derive 1.0.164 checksum:d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68 +│ │ ├── syn 2.0.18 checksum:32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e +│ │ ├── quote 1.0.28 checksum:1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488 +│ │ └── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 │ ├── rand_core 0.6.4 checksum:ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c │ ├── ed25519 2.2.2 checksum:60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d │ │ ├── signature 2.1.0 checksum:5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500 @@ -192,7 +159,6 @@ soroban-env-host 0.0.17 git+https://github.com/stellar/rs-soroban-env?rev=f5c6c0 │ │ └── proc-macro2 1.0.60 checksum:dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406 │ ├── cpufeatures 0.2.8 checksum:03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c │ └── cfg-if 1.0.0 checksum:baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd -├── curve25519-dalek 4.0.0 checksum:f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2 └── backtrace 0.3.67 checksum:233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca ├── rustc-demangle 0.1.23 checksum:d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76 ├── object 0.30.4 checksum:03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385 diff --git a/src/transactions/TransactionFrame.cpp b/src/transactions/TransactionFrame.cpp index 54e5f02a72..17800956c9 100644 --- a/src/transactions/TransactionFrame.cpp +++ b/src/transactions/TransactionFrame.cpp @@ -239,6 +239,11 @@ TransactionFrame::getResources() const int64_t txSize = xdr::xdr_size(mEnvelope.v1().tx); int64_t const opCount = 1; + // When doing fee calculation, the rust host will include readWrite + // entries in the read related fees. However, this resource calculation + // is used for constructing TX sets before invoking the host, so we need + // to sum readOnly size and readWrite size for correct resource limits + // here. return Resource({opCount, r.instructions, txSize, r.readBytes, r.writeBytes, static_cast(r.footprint.readOnly.size() + @@ -789,8 +794,7 @@ TransactionFrame::computeSorobanResourceFee( cxxResources.instructions = txResources.instructions; cxxResources.read_entries = - static_cast(txResources.footprint.readOnly.size() + - txResources.footprint.readWrite.size()); + static_cast(txResources.footprint.readOnly.size()); cxxResources.write_entries = static_cast(txResources.footprint.readWrite.size()); diff --git a/src/transactions/test/InvokeHostFunctionTests.cpp b/src/transactions/test/InvokeHostFunctionTests.cpp index 02d091946d..5c11c33097 100644 --- a/src/transactions/test/InvokeHostFunctionTests.cpp +++ b/src/transactions/test/InvokeHostFunctionTests.cpp @@ -317,11 +317,313 @@ deployContractWithSourceAccount(Application& app, RustBuf const& contractWasm, app, contractWasm, uploadResources, createResources, salt); } +// Fee constants from rs-soroban-env/soroban-env-host/src/fees.rs +constexpr int64_t INSTRUCTION_INCREMENT = 10000; +constexpr int64_t DATA_SIZE_1KB_INCREMENT = 1024; +constexpr int64_t TX_BASE_RESULT_SIZE = 300; + +static int64_t +computeFeePerIncrement(int64_t resourceVal, int64_t feeRate, int64_t increment) +{ + // ceiling division for (resourceVal * feeRate) / increment + int64_t num = (resourceVal * feeRate); + return (num + increment - 1) / increment; +}; + +static int64_t +getRentFeeForBytes(int64_t entrySize, uint32_t numLedgersToBump, + SorobanNetworkConfig const& cfg, bool isPersistent) +{ + auto num = entrySize * cfg.feeWrite1KB() * numLedgersToBump; + auto storageCoef = + isPersistent + ? cfg.stateExpirationSettings().persistentRentRateDenominator + : cfg.stateExpirationSettings().tempRentRateDenominator; + + auto denom = DATA_SIZE_1KB_INCREMENT * storageCoef; + + // Ceiling division + return (num + denom - 1) / denom; +} + +static int64_t +getExpirationEntryWriteFee(SorobanNetworkConfig const& cfg) +{ + LedgerEntry le; + le.data.type(EXPIRATION); + + auto writeSize = xdr::xdr_size(le); + auto writeFee = computeFeePerIncrement(writeSize, cfg.feeWrite1KB(), + DATA_SIZE_1KB_INCREMENT); + writeFee += cfg.feeWriteLedgerEntry(); + return writeFee; +} + +static int64_t +getRentFeeForBump(Application& app, LedgerKey const& key, uint32_t newLifetime, + SorobanNetworkConfig const& cfg) +{ + LedgerTxn ltx(app.getLedgerTxnRoot()); + auto ledgerSeq = ltx.getHeader().ledgerSeq; + auto expirationKey = getExpirationKey(key); + auto expirationLtxe = ltx.loadWithoutRecord(expirationKey); + releaseAssert(expirationLtxe); + + ExpirationEntry const& expirationEntry = + expirationLtxe.current().data.expiration(); + + uint32_t numLedgersToBump = 0; + if (isLive(expirationLtxe.current(), ledgerSeq)) + { + auto ledgerToBumpTo = ledgerSeq + newLifetime; + if (expirationEntry.expirationLedgerSeq >= ledgerToBumpTo) + { + return 0; + } + + numLedgersToBump = ledgerToBumpTo - expirationEntry.expirationLedgerSeq; + } + else + { + // Expired entries are skipped, pay no rent fee + return 0; + } + + auto txle = ltx.loadWithoutRecord(key); + releaseAssert(txle); + + auto entrySize = xdr::xdr_size(txle.current()); + auto rentFee = getRentFeeForBytes(entrySize, numLedgersToBump, cfg, + isPersistentEntry(key)); + + return rentFee + getExpirationEntryWriteFee(cfg); +} + +TEST_CASE("non-refundable resource metering", "[tx][soroban]") +{ + VirtualClock clock; + auto app = createTestApplication(clock, getTestConfig()); + overrideSorobanNetworkConfigForTest(*app); + + uniform_int_distribution feeDist(1, 100'000); + modifySorobanNetworkConfig(*app, [&feeDist](SorobanNetworkConfig& cfg) { + cfg.mFeeRatePerInstructionsIncrement = feeDist(Catch::rng()); + cfg.mFeeReadLedgerEntry = feeDist(Catch::rng()); + cfg.mFeeWriteLedgerEntry = feeDist(Catch::rng()); + cfg.mFeeRead1KB = feeDist(Catch::rng()); + cfg.mFeeWrite1KB = feeDist(Catch::rng()); + cfg.mFeeHistorical1KB = feeDist(Catch::rng()); + cfg.mFeeTransactionSize1KB = feeDist(Catch::rng()); + }); + + SorobanNetworkConfig const& cfg = [&] { + LedgerTxn ltx(app->getLedgerTxnRoot()); + return app->getLedgerManager().getSorobanNetworkConfig(ltx); + }(); + + Operation op; + op.body.type(INVOKE_HOST_FUNCTION); + auto& ihf = op.body.invokeHostFunctionOp().hostFunction; + ihf.type(HOST_FUNCTION_TYPE_INVOKE_CONTRACT); + + SorobanResources resources; + resources.instructions = 0; + resources.readBytes = 0; + resources.writeBytes = 0; + + auto root = TestAccount::createRoot(*app); + + // The following computations are copies of compute_transaction_resource_fee + // in rs-soroban-env/soroban-env-host/src/fees.rs. This is reimplemented + // here so that we can check if the Cxx bridge introduced any fee related + // bugs. + + // Fees that depend on TX size, historicalFee and bandwidthFee + auto txSizeFees = [&](TransactionFrameBasePtr tx) { + int64_t txSize = static_cast(xdr::xdr_size(tx->getEnvelope())); + int64_t historicalFee = computeFeePerIncrement( + txSize + TX_BASE_RESULT_SIZE, cfg.mFeeHistorical1KB, + DATA_SIZE_1KB_INCREMENT); + + int64_t bandwidthFee = computeFeePerIncrement( + txSize, cfg.feeTransactionSize1KB(), DATA_SIZE_1KB_INCREMENT); + + return historicalFee + bandwidthFee; + }; + + auto computeFee = [&] { + return computeFeePerIncrement(resources.instructions, + cfg.feeRatePerInstructionsIncrement(), + INSTRUCTION_INCREMENT); + }; + + auto entryReadFee = [&] { + return (resources.footprint.readOnly.size() + + resources.footprint.readWrite.size()) * + cfg.feeReadLedgerEntry(); + }; + + auto entryWriteFee = [&] { + return resources.footprint.readWrite.size() * cfg.feeWriteLedgerEntry(); + }; + + auto readBytesFee = [&] { + return computeFeePerIncrement(resources.readBytes, cfg.feeRead1KB(), + DATA_SIZE_1KB_INCREMENT); + }; + + auto writeBytesFee = [&] { + return computeFeePerIncrement(resources.writeBytes, cfg.feeWrite1KB(), + DATA_SIZE_1KB_INCREMENT); + }; + + auto checkFees = [&](int64_t expectedNonRefundableFee, + std::shared_ptr rootTX) { + LedgerTxn ltx(app->getLedgerTxnRoot()); + + // This will compute soroban fees + REQUIRE(rootTX->checkValid(*app, ltx, 0, 0, 0)); + + auto actualFeePair = std::dynamic_pointer_cast(rootTX) + ->getSorobanResourceFee(); + REQUIRE(actualFeePair); + REQUIRE(expectedNonRefundableFee == actualFeePair->non_refundable_fee); + + auto inclusionFee = getMinInclusionFee(*rootTX, ltx.getHeader()); + + // Check that minimum fee succeeds + auto minimalTX = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, + expectedNonRefundableFee + inclusionFee, 0); + REQUIRE(minimalTX->checkValid(*app, ltx, 1, 0, 0)); + + // Check that just below minimum fee fails + auto badTX = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, + expectedNonRefundableFee + inclusionFee - 1, 0); + REQUIRE(!badTX->checkValid(*app, ltx, 2, 0, 0)); + }; + + // In the following tests, we isolate a single fee to test by zeroing out + // every other resource, as much as is possible + SECTION("tx size fees") + { + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Resources are all null, only include TX size based fees + auto expectedFee = txSizeFees(tx); + checkFees(expectedFee, tx); + } + + SECTION("compute fee") + { + resources.instructions = feeDist(Catch::rng()); + + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Should only have instruction and TX size fees + auto expectedFee = txSizeFees(tx) + computeFee(); + checkFees(expectedFee, tx); + } + + uniform_int_distribution<> numKeysDist(1, 10); + SECTION("entry read/write fee") + { + SECTION("RO Only") + { + auto size = numKeysDist(Catch::rng()); + for (auto const& e : + LedgerTestUtils::generateValidUniqueLedgerEntriesWithTypes( + {CONTRACT_DATA, CONTRACT_CODE}, size)) + { + resources.footprint.readOnly.emplace_back(LedgerEntryKey(e)); + } + + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Only read entry fees and TX size fees + auto expectedFee = txSizeFees(tx) + entryReadFee(); + checkFees(expectedFee, tx); + } + + SECTION("RW Only") + { + auto size = numKeysDist(Catch::rng()); + for (auto const& e : + LedgerTestUtils::generateValidUniqueLedgerEntriesWithTypes( + {CONTRACT_DATA, CONTRACT_CODE}, size)) + { + resources.footprint.readWrite.emplace_back(LedgerEntryKey(e)); + } + + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Only read entry, write entry, and TX size fees + auto expectedFee = + txSizeFees(tx) + entryReadFee() + entryWriteFee(); + checkFees(expectedFee, tx); + } + + SECTION("RW and RO") + { + auto size = numKeysDist(Catch::rng()); + for (auto const& e : + LedgerTestUtils::generateValidUniqueLedgerEntriesWithTypes( + {CONTRACT_DATA, CONTRACT_CODE}, size)) + { + resources.footprint.readOnly.emplace_back(LedgerEntryKey(e)); + } + + size = numKeysDist(Catch::rng()); + for (auto const& e : + LedgerTestUtils::generateValidUniqueLedgerEntriesWithTypes( + {CONTRACT_DATA, CONTRACT_CODE}, size)) + { + resources.footprint.readWrite.emplace_back(LedgerEntryKey(e)); + } + + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Only read entry, write entry, and TX size fees + auto expectedFee = + txSizeFees(tx) + entryReadFee() + entryWriteFee(); + checkFees(expectedFee, tx); + } + } + + uniform_int_distribution bytesDist(1, 100'000); + SECTION("readBytes fee") + { + resources.readBytes = bytesDist(Catch::rng()); + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Only readBytes and TX size fees + auto expectedFee = txSizeFees(tx) + readBytesFee(); + checkFees(expectedFee, tx); + } + + SECTION("writeBytes fee") + { + resources.writeBytes = bytesDist(Catch::rng()); + auto tx = sorobanTransactionFrameFromOps( + app->getNetworkID(), root, {op}, {}, resources, UINT32_MAX, 0); + + // Only writeBytes and TX size fees + auto expectedFee = txSizeFees(tx) + writeBytesFee(); + checkFees(expectedFee, tx); + } +} + TEST_CASE("basic contract invocation", "[tx][soroban]") { VirtualClock clock; auto cfg = getTestConfig(); - cfg.EXPERIMENTAL_BUCKETLIST_DB = false; auto app = createTestApplication(clock, cfg); overrideSorobanNetworkConfigForTest(*app); @@ -737,7 +1039,8 @@ TEST_CASE("contract storage", "[tx][soroban]") xdr::xvector const& readWrite, uint32_t writeBytes, SCAddress const& contractAddress, SCSymbol const& functionName, - std::vector const& args) + std::vector const& args, + std::optional refundableFeeOp = {}) -> std::tuple, std::shared_ptr> { Operation op; @@ -754,8 +1057,14 @@ TEST_CASE("contract storage", "[tx][soroban]") resources.readBytes = 5000; resources.writeBytes = writeBytes; - auto tx = sorobanTransactionFrameFromOps( - app->getNetworkID(), root, {op}, {}, resources, 200'000, 40'000); + uint32_t refundableFee = 40'000; + if (refundableFeeOp) + { + refundableFee = *refundableFeeOp; + } + auto tx = + sorobanTransactionFrameFromOps(app->getNetworkID(), root, {op}, {}, + resources, 200'000, refundableFee); auto ltx = std::make_shared(app->getLedgerTxnRoot()); auto txm = std::make_shared( ltx->loadHeader().current().ledgerVersion); @@ -941,6 +1250,36 @@ TEST_CASE("contract storage", "[tx][soroban]") bumpLowHigh(key, type, bumpAmount, bumpAmount); }; + auto increaseEntrySizeAndBump = + [&](std::string const& key, uint32_t numKiloBytes, uint32_t lowLifetime, + uint32_t highLifetime, xdr::xvector const& readOnly, + xdr::xvector const& readWrite, bool expectSuccess, + uint32_t refundableFee) { + auto keySymbol = makeSymbolSCVal(key); + auto numKiloBytesU32 = makeU32(numKiloBytes); + auto lowLifetimeU32 = makeU32(lowLifetime); + auto highLifetimeU32 = makeU32(highLifetime); + + std::string funcStr = "replace_with_bytes_and_bump"; + + // TODO: Better bytes to write value + auto [tx, ltx, txm] = createTx( + readOnly, readWrite, 2000, contractID, makeSymbol(funcStr), + {keySymbol, numKiloBytesU32, lowLifetimeU32, highLifetimeU32}, + refundableFee); + + if (expectSuccess) + { + REQUIRE(tx->apply(*app, *ltx, *txm)); + } + else + { + REQUIRE(!tx->apply(*app, *ltx, *txm)); + } + + ltx->commit(); + }; + auto runExpirationOp = [&](TestAccount& root, TransactionFrameBasePtr tx, int64_t refundableFee, int64_t expectedRefundableFeeCharged) { @@ -988,8 +1327,14 @@ TEST_CASE("contract storage", "[tx][soroban]") }; auto bumpOp = [&](uint32_t bumpAmount, - xdr::xvector const& readOnly, - int64_t expectedRefundableFeeCharged) { + xdr::xvector const& readOnly) { + int64_t expectedRefundableFeeCharged = 0; + for (auto const& key : readOnly) + { + expectedRefundableFeeCharged += + getRentFeeForBump(*app, key, bumpAmount, sorobanConfig); + } + Operation bumpOp; bumpOp.body.type(BUMP_FOOTPRINT_EXPIRATION); bumpOp.body.bumpFootprintExpirationOp().ledgersToExpire = bumpAmount; @@ -1189,7 +1534,7 @@ TEST_CASE("contract storage", "[tx][soroban]") { // Restore Instance and WASM restoreOp(contractKeys, - 163 /* rent bump */ + 40000 /* two LE-writes */); + 161 /* rent bump */ + 40000 /* two LE-writes */); // Instance should now be useable putWithFootprint( @@ -1225,7 +1570,7 @@ TEST_CASE("contract storage", "[tx][soroban]") { // Only restore WASM restoreOp({contractKeys[1]}, - 114 /* rent bump */ + 20000 /* one LE write */); + 112 /* rent bump */ + 20000 /* one LE write */); // invocation should fail putWithFootprint( @@ -1243,16 +1588,16 @@ TEST_CASE("contract storage", "[tx][soroban]") { // Restore Instance and WASM restoreOp(contractKeys, - 163 /* rent bump */ + 40000 /* two LE writes */); + 161 /* rent bump */ + 40000 /* two LE writes */); auto instanceBumpAmount = 10'000; auto wasmBumpAmount = 15'000; // bump instance - bumpOp(instanceBumpAmount, {contractKeys[0]}, 20050); + bumpOp(instanceBumpAmount, {contractKeys[0]}); // bump WASM - bumpOp(wasmBumpAmount, {contractKeys[1]}, 20225); + bumpOp(wasmBumpAmount, {contractKeys[1]}); checkEntry(contractKeys[0], ledgerSeq + instanceBumpAmount); checkEntry(contractKeys[1], ledgerSeq + wasmBumpAmount); @@ -1355,14 +1700,17 @@ TEST_CASE("contract storage", "[tx][soroban]") "key3", ContractDataDurability::PERSISTENT, ledgerSeq + 50'000); // Bump multiple keys to live 10100 ledger from now - bumpOp(10100, - {contractDataKey(contractID, makeSymbolSCVal("key"), - ContractDataDurability::PERSISTENT), - contractDataKey(contractID, makeSymbolSCVal("key2"), - ContractDataDurability::PERSISTENT), - contractDataKey(contractID, makeSymbolSCVal("key3"), - ContractDataDurability::PERSISTENT)}, - 40097); // only 2 ledger writes because key3 won't be bumped + bumpOp( + 10100, + {contractDataKey(contractID, makeSymbolSCVal("key"), + ContractDataDurability::PERSISTENT), + contractDataKey(contractID, makeSymbolSCVal("key2"), + ContractDataDurability::PERSISTENT), + contractDataKey( + contractID, makeSymbolSCVal("key3"), + ContractDataDurability::PERSISTENT)}); // only 2 ledger writes + // because key3 won't be + // bumped checkContractDataExpirationLedger( "key", ContractDataDurability::PERSISTENT, ledgerSeq + 10'100); @@ -1420,7 +1768,7 @@ TEST_CASE("contract storage", "[tx][soroban]") 1; // Bump instance and WASM so that they don't expire during the test - bumpOp(10'000, contractKeys, 40194); + bumpOp(10'000, contractKeys); put("key", 0, ContractDataDurability::PERSISTENT); checkContractDataExpirationLedger( @@ -1455,7 +1803,7 @@ TEST_CASE("contract storage", "[tx][soroban]") ContractDataDurability::PERSISTENT); // Bump operation should skip expired entries - bumpOp(1'000, {lk}, 0); + bumpOp(1'000, {lk}); // Make sure expirationLedger is unchanged by bumpOp checkContractDataExpirationLedger( @@ -1513,6 +1861,99 @@ TEST_CASE("contract storage", "[tx][soroban]") "key", ContractDataDurability::TEMPORARY, newExpirationLedger); } + SECTION("charge rent fees for storage resize") + { + auto resizeKilobytes = 1; + put("key1", 0, ContractDataDurability::PERSISTENT); + auto key1lk = + contractDataKey(contractID, makeSymbolSCVal("key1"), PERSISTENT); + + auto startingSizeBytes = 0; + { + LedgerTxn ltx(app->getLedgerTxnRoot()); + auto txle = ltx.loadWithoutRecord(key1lk); + REQUIRE(txle); + startingSizeBytes = xdr::xdr_size(txle.current()); + } + + // First, resize a key with large fee to guarantee success + increaseEntrySizeAndBump("key1", resizeKilobytes, 0, 0, contractKeys, + {key1lk}, true, 40'000); + + auto sizeDeltaBytes = 0; + { + LedgerTxn ltx(app->getLedgerTxnRoot()); + auto txle = ltx.loadWithoutRecord(key1lk); + REQUIRE(txle); + sizeDeltaBytes = xdr::xdr_size(txle.current()) - startingSizeBytes; + } + + // Now that we know the size delta, we can calculate the expected rent + // and check that another entry resize charges fee correctly + put("key2", 0, ContractDataDurability::PERSISTENT); + + auto initialLifetime = + stateExpirationSettings.minPersistentEntryExpiration; + + SECTION("resize with no bump") + { + auto expectedRentFee = getRentFeeForBytes( + sizeDeltaBytes, initialLifetime, sorobanConfig, + /*isPersistent=*/true); + + // refundableFee = rent fee + (event size + return val) fee. So + // in order to succeed refundableFee needs to be expectedRentFee + // + 1 to account for the return val size. We are not changing the + // expirationLedgerSeq, so there is no ExpirationEntry write charge + auto refundableFee = expectedRentFee + 1; + increaseEntrySizeAndBump( + "key2", resizeKilobytes, 0, 0, contractKeys, + {contractDataKey(contractID, makeSymbolSCVal("key2"), + PERSISTENT)}, + false, refundableFee - 1); + + // Size change should succeed with enough refundable fee + increaseEntrySizeAndBump( + "key2", resizeKilobytes, 0, 0, contractKeys, + {contractDataKey(contractID, makeSymbolSCVal("key2"), + PERSISTENT)}, + true, refundableFee); + } + + SECTION("resize and bump") + { + auto newLifetime = initialLifetime + 1000; + + // New bytes are charged rent for previous lifetime and new lifetime + auto resizeRentFee = + getRentFeeForBytes(sizeDeltaBytes, newLifetime, sorobanConfig, + /*isPersistent=*/true); + + // Initial bytes just charged for new lifetime + auto bumpFee = getRentFeeForBytes( + startingSizeBytes, newLifetime - initialLifetime, sorobanConfig, + /*isPersistent=*/true); + + // refundableFee = rent fee + (event size + return val) fee. So in + // order to success refundableFee needs to be expectedRentFee + // + 1 to account for the return val size. + auto refundableFee = resizeRentFee + bumpFee + + getExpirationEntryWriteFee(sorobanConfig) + 1; + increaseEntrySizeAndBump( + "key2", resizeKilobytes, newLifetime, newLifetime, contractKeys, + {contractDataKey(contractID, makeSymbolSCVal("key2"), + PERSISTENT)}, + false, refundableFee - 1); + + // Size change should succeed with enough refundable fee + increaseEntrySizeAndBump( + "key2", resizeKilobytes, newLifetime, newLifetime, contractKeys, + {contractDataKey(contractID, makeSymbolSCVal("key2"), + PERSISTENT)}, + true, refundableFee); + } + } + SECTION("max expiration") { // Check that attempting to bump past max ledger results in error