From 3687713e04a65af471dc536270e47840ce483b0f Mon Sep 17 00:00:00 2001 From: Qoder-Undefined Date: Wed, 22 Jul 2026 15:19:37 +0100 Subject: [PATCH 1/4] fix the claim refund donors --- soroban-sdk-26.0.1.tar.gz | Bin 0 -> 161631 bytes .../soroban-sdk-26.0.1/.cargo_vcs_info.json | 6 + temp_sdk/soroban-sdk-26.0.1/Cargo.lock | 1985 +++++++++++++++ temp_sdk/soroban-sdk-26.0.1/Cargo.toml | 198 ++ temp_sdk/soroban-sdk-26.0.1/Cargo.toml.orig | 83 + temp_sdk/soroban-sdk-26.0.1/README.md | 60 + temp_sdk/soroban-sdk-26.0.1/build.rs | 50 + temp_sdk/soroban-sdk-26.0.1/docs/README.md | 7 + .../soroban-sdk-26.0.1/docs/contracttrait.md | 156 ++ .../doctest_fixtures/README.md | 8 + temp_sdk/soroban-sdk-26.0.1/src/_features.rs | 141 ++ temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs | 324 +++ .../src/_migrating/v23_archived_testing.rs | 176 ++ .../src/_migrating/v23_contractevent.rs | 438 ++++ .../src/_migrating/v25_bn254.rs | 138 + .../src/_migrating/v25_contracttrait.rs | 335 +++ .../src/_migrating/v25_event_testing.rs | 154 ++ .../src/_migrating/v25_poseidon.rs | 100 + .../src/_migrating/v25_resource_limits.rs | 145 ++ temp_sdk/soroban-sdk-26.0.1/src/address.rs | 450 ++++ .../soroban-sdk-26.0.1/src/address_payload.rs | 126 + .../src/alloc/bump_pointer.rs | 122 + temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs | 61 + .../soroban-sdk-26.0.1/src/arbitrary_extra.rs | 71 + temp_sdk/soroban-sdk-26.0.1/src/auth.rs | 108 + temp_sdk/soroban-sdk-26.0.1/src/bytes.rs | 1839 ++++++++++++++ .../src/constructor_args.rs | 32 + temp_sdk/soroban-sdk-26.0.1/src/crypto.rs | 396 +++ .../src/crypto/bls12_381.rs | 1123 +++++++++ .../soroban-sdk-26.0.1/src/crypto/bn254.rs | 727 ++++++ .../soroban-sdk-26.0.1/src/crypto/utils.rs | 64 + temp_sdk/soroban-sdk-26.0.1/src/deploy.rs | 469 ++++ temp_sdk/soroban-sdk-26.0.1/src/env.rs | 2240 +++++++++++++++++ temp_sdk/soroban-sdk-26.0.1/src/error.rs | 37 + temp_sdk/soroban-sdk-26.0.1/src/events.rs | 162 ++ .../src/into_val_for_contract_fn.rs | 46 + temp_sdk/soroban-sdk-26.0.1/src/iter.rs | 87 + temp_sdk/soroban-sdk-26.0.1/src/ledger.rs | 184 ++ temp_sdk/soroban-sdk-26.0.1/src/lib.rs | 1255 +++++++++ temp_sdk/soroban-sdk-26.0.1/src/logs.rs | 170 ++ temp_sdk/soroban-sdk-26.0.1/src/map.rs | 1169 +++++++++ .../soroban-sdk-26.0.1/src/muxed_address.rs | 416 +++ temp_sdk/soroban-sdk-26.0.1/src/num.rs | 1123 +++++++++ temp_sdk/soroban-sdk-26.0.1/src/prng.rs | 586 +++++ .../soroban-sdk-26.0.1/src/spec_shaking.rs | 433 ++++ temp_sdk/soroban-sdk-26.0.1/src/storage.rs | 775 ++++++ temp_sdk/soroban-sdk-26.0.1/src/string.rs | 417 +++ temp_sdk/soroban-sdk-26.0.1/src/symbol.rs | 299 +++ temp_sdk/soroban-sdk-26.0.1/src/tests.rs | 55 + temp_sdk/soroban-sdk-26.0.1/src/testutils.rs | 798 ++++++ .../src/testutils/arbitrary.rs | 2235 ++++++++++++++++ .../src/testutils/cost_estimate.rs | 153 ++ .../src/testutils/mock_auth.rs | 145 ++ .../soroban-sdk-26.0.1/src/testutils/sign.rs | 97 + .../src/testutils/storage.rs | 41 + temp_sdk/soroban-sdk-26.0.1/src/token.rs | 491 ++++ .../src/try_from_val_for_contract_fn.rs | 58 + temp_sdk/soroban-sdk-26.0.1/src/tuple.rs | 73 + temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs | 96 + temp_sdk/soroban-sdk-26.0.1/src/vec.rs | 2000 +++++++++++++++ temp_sdk/soroban-sdk-26.0.1/src/xdr.rs | 118 + .../soroban-sdk-26.0.1/test_wasms/README.md | 6 + 62 files changed, 25857 insertions(+) create mode 100644 soroban-sdk-26.0.1.tar.gz create mode 100644 temp_sdk/soroban-sdk-26.0.1/.cargo_vcs_info.json create mode 100644 temp_sdk/soroban-sdk-26.0.1/Cargo.lock create mode 100644 temp_sdk/soroban-sdk-26.0.1/Cargo.toml create mode 100644 temp_sdk/soroban-sdk-26.0.1/Cargo.toml.orig create mode 100644 temp_sdk/soroban-sdk-26.0.1/README.md create mode 100644 temp_sdk/soroban-sdk-26.0.1/build.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/docs/README.md create mode 100644 temp_sdk/soroban-sdk-26.0.1/docs/contracttrait.md create mode 100644 temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_features.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/address.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/auth.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/bytes.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/deploy.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/env.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/error.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/events.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/iter.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/ledger.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/lib.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/logs.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/map.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/num.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/prng.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/storage.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/string.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/symbol.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/tests.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/token.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/tuple.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/vec.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/src/xdr.rs create mode 100644 temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md diff --git a/soroban-sdk-26.0.1.tar.gz b/soroban-sdk-26.0.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ac724097e92e92473a1643261e4d399fe239e2bd GIT binary patch literal 161631 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 E_in+c0N5#xxcugzMsT0 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Ò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 z zy$q0xGeIiOyt5CTJKbw^)bIFL@o0+c8QEfo{wsVs1!J#!0&ec^mS@^lb9Up(tbLcZ zQ{s!~Sf#?9^GZr2jtmQu35Cgwj9|bIgCO)-Ph{Yc?un;KLR5t|m*!BLD-Fw1tQ0rB zt}xV$fm1Y7UPquw48Dqqg{#HKzWrp@=N~6srwCT_@ecyCIVAVn$FOaqva%Y8iB#>QC};4 z++e#ZglhE#xAeS{nI;}PL=a~ngl#m0SU{}vL@8;wu%aVCeKw*L`c(J6BB#$Z=V19U z7$SUDwP6yyv)C9KbKXsI8bl+5$}VA{i`hP6rOyZml{M6svqqF?J`e_J-Zu!(*N1VG zktamgq3~>S^BJ8KVh=<7aR?_uP89xr=N6S%O-*lm(TsK)mYc8j8g4*kC5!U~e${>d zNV+e+x)9U6jnP)L#@56GgdS1*19-CnWnz`D! z8jJXHkZukjTod1Ey*J|NhC7PR6; z>9mXLj|#+P;~?EO}~4Lf!0!QPG2b# zQvg=O(TgnmFj3S&SHj&X1QdJ{?~1sEdvTqlGvr0UXeBs?g<1*i6-8P} zMEjVxbx*I@x~K8h5o3K~HO}zeH_RB#Y%%=$W(aT;1l>O7P@7?(#-k>Vw`;-sdJKvb zkfc&mgW(%}@;mhts&Yvl=JlQj0T{g5&U^D|FrRc7Z`2U2QfbL$fs8<>$IDv>>zd+<a!#Xw`BcrOKI7eiE6Y~Xh@ZK0&D~@Jo>M# z_4Qh@q;7p7;u+Z;z>t=+L*#7{`R7H)$_yC^ZoEZ#ukgfS<29D=a>|~DR;)R!vR;4( z(-QkJA?xm+cp989m?Xk~>&N875XXX3C_|#09XH8uU>`qX1ljS(bd#510_&y3Ir9Z) z&Fn^lG8*7R!a=ZVRdgmcV?4Mf4AbVwEFq^slp8Rk=Y@7y8o3B{1)j(OO4FOeYxxyr>fmp2OBSYQ5tfIh_b%Wwv&Ka@d6-fzf^) zU9Ly?uG1jRUWojy@GQ3az3;jwGY65ZV%&+cZlrjIJNBaz@HnShRKh0C3LDXDA=E;` zfFu$I>O!zga>}N4lKcWL8EVTp+)yel(O!BZpr~?{uR+N~XrN)=1A&(a6Q+10@VM7f zkEQ&fWCB51fR1JALwLu`Puo)n<$3Yi6v-&C)U& zE@2bF6mT%ic-y2QYSMBWsxXGQDZHgqADW}&0%4YHET-^z{dfaMJW?L*dB-d#obe|@ z;}u4G?Js26rhImPuy!N59AdJl?<3~Q`LNq5S8|j-D5dNd3Y(M~^iVBv5-|PJetKJ0 zSq#oQx9!ZJVFZBJA zPBTA5M@=o55Jj`AlBdkeXZPop6=!c_1&udszeuk38aq4;b22I@peD8z?j`!uO$(PQ zb$M0&q|yh6y!-Vf3SeXTm zFmxF7P)$x^&U4yD;wXyef|Wt#JC+a5NKxKti_Dy!sN4FA7JnP3o!V<(v1&kR zaa0HQfC{2HJ_qZ^F8}7I{JTAai&#nz({DB2gsc>QI2bqKqMf5*14YdTs4x!(MIKIv zNiGWHe#t-#9|{-?{OZ)K+dg0bg4Z?QLK5;5$0VTf`E;(kpu4zl^NR{A&jR~XuOSLv zIVcRT=74M!NIqV;;4DxxKG-2qV|RX>-5~*Z2XM7a)!>zJiI{yE>fU3 zy8HYN^V*r0I}fM%F~J`cVenmgUnfkrU;twHg7d@4&5cr51bgTVf6&c&0EkPGfj|zz z+pxYg9BKE*tgMDLQueh3C>#zLgLHuE-_OJDAd2pnk960A(|8k>=x$HONnw}pU$7u% z0;C8hlfRTUyd<>P${zs?gdT(w2L4fHz@Ol=m6^~a1^MW-*VyYF`ZIAhq!xVebdV({ zsYmh}0La)|&z#xozf1>COo!yI@hmlw1{_pcNb~+{#x}Nhh~|RfKLn0zGQ~hTswLs{ zWa|-PwCi+v3iYvLS;1CEhCVRZ@y+2_lwCq07-+Vo5?iisJd*S?C4t0bFtiMU{NG(_Y|aY~2#%KTe4jD5kY?6ACrPUhfaXo5g*zC?ledycIS@wIHEAYhAg;x2fJi; z8>DmXUvy@0dA3f*5DZqvA;x-G1MPqpWBqVDJ#h|7&Y4{y&=*@Hz-odqHsZo24o`_8gO9dWH|w^f7pGKG`tV{$7CWv&|{d4{0CyMU&_Y%f?Yjd z_t&rc>(~8t;r$iOKi2+Y?R#R#{ljg#ur*+Z=J)8{1l{Vi-Vv+=)VfnTIQWqvF)$yH zpdL^fQHlUYpOPcR0}*sL$VxL;+S*uSC)-%-9` zR^*%Q9fi!`^TZUh(8zx9X>9DDKpAx8+f72k{=SMrSfC8X6+wpwKpWSwN`Za7sm$v} zEiAOFzc9qV%ErEsWgW$klUFh(TOir#e-S4txxm z1UZAvK3%EJXlTJ(>)>5g0lS{zCHyhs+lWN&TEeX(bpT*MpTFZSAaWPajQyQa2n$?8 zI6sEkQKA~?Q@)TunaBC>=;N1jbU9Lj&hGbXi6EZGb4Ab^N){P0=|ttw%h6UU6~ae-P(->D zlSf*zJ;$OHX9*Z_FGI1SRalzDwYDn-00sFP7zL>+vpr)x8t5i*G_(6C$Eac*Ee z_ax|w%epUz?3lgXHQuj-S?b-|cw(==rFfLg!mMtol{l6<5$f<(fw0!=WnId!Y`d!T z%n$~W=Ht3j;dt-p=K3|}zSOv#t3C&z_%hXftKY-IzKo?mDyxg_0Ks;-*hWCc3fe*! zlu?VjH?j*GQDp@%BC76>8NHqU&MQjwCxcC3K∓n_CQ~injPc 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 S=l#z+@bmvQp7"] +build = "build.rs" +exclude = [ + "test_snapshots/", + "src/tests/", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Soroban SDK." +homepage = "https://github.com/stellar/rs-soroban-sdk" +readme = "README.md" +license = "Apache-2.0" +repository = "https://github.com/stellar/rs-soroban-sdk" + +[package.metadata.docs.rs] +all-features = true + +[features] +alloc = [] +docs = [] +experimental_spec_shaking_v2 = ["soroban-sdk-macros/experimental_spec_shaking_v2"] +hazmat = [ + "hazmat-crypto", + "hazmat-address", +] +hazmat-address = [] +hazmat-crypto = [] +testutils = [ + "soroban-sdk-macros/testutils", + "soroban-env-host/testutils", + "soroban-ledger-snapshot/testutils", + "dep:ed25519-dalek", + "dep:arbitrary", + "dep:derive_arbitrary", + "dep:ctor", + "dep:soroban-ledger-snapshot", +] + +[lib] +name = "soroban_sdk" +path = "src/lib.rs" +doctest = false + +[dependencies.bytes-lit] +version = "0.0.5" + +[dependencies.soroban-sdk-macros] +version = "26.0.1" + +[dependencies.stellar-strkey] +version = "=0.0.16" + +[dependencies.visibility] +version = "0.1.1" + +[dev-dependencies.arbitrary] +version = "~1.3.0" +features = ["derive"] + +[dev-dependencies.ark-bls12-381] +version = "0.5" +features = ["curve"] +default-features = false + +[dev-dependencies.ark-bn254] +version = "0.5" +features = ["curve"] +default-features = false + +[dev-dependencies.ark-ff] +version = "0.5" +default-features = false + +[dev-dependencies.ctor] +version = "0.5.0" + +[dev-dependencies.derive_arbitrary] +version = "~1.3.0" + +[dev-dependencies.ed25519-dalek] +version = "2.0.0" + +[dev-dependencies.expect-test] +version = "1.4.1" + +[dev-dependencies.hex] +version = "0.4.3" + +[dev-dependencies.libfuzzer-sys] +version = "0.4.7" + +[dev-dependencies.proptest] +version = "1.2.0" + +[dev-dependencies.proptest-arbitrary-interop] +version = "0.1.0" + +[dev-dependencies.rand] +version = "0.8.5" + +[dev-dependencies.sha2] +version = "0.10.7" + +[dev-dependencies.soroban-env-host] +version = "=26.1.3" +features = ["testutils"] + +[dev-dependencies.soroban-ledger-snapshot] +version = "26.0.1" +features = ["testutils"] + +[dev-dependencies.soroban-sdk-macros] +version = "26.0.1" +features = ["testutils"] + +[dev-dependencies.soroban-spec] +version = "26.0.1" + +[dev-dependencies.stellar-xdr] +version = "=26.0.1" +features = [ + "curr", + "curr", + "std", +] +default-features = false + +[build-dependencies.crate-git-revision] +version = "0.0.6" + +[build-dependencies.rustc_version] +version = "0.4.1" + +[target.'cfg(not(target_family="wasm"))'.dependencies.arbitrary] +version = "~1.3.0" +features = ["derive"] +optional = true + +[target.'cfg(not(target_family="wasm"))'.dependencies.ctor] +version = "0.5.0" +optional = true + +[target.'cfg(not(target_family="wasm"))'.dependencies.curve25519-dalek] +version = "4.1.3" +features = ["digest"] +optional = true + +[target.'cfg(not(target_family="wasm"))'.dependencies.derive_arbitrary] +version = "~1.3.0" +optional = true + +[target.'cfg(not(target_family="wasm"))'.dependencies.ed25519-dalek] +version = "2.1.1" +features = ["rand_core"] +optional = true + +[target.'cfg(not(target_family="wasm"))'.dependencies.rand] +version = "0.8.5" + +[target.'cfg(not(target_family="wasm"))'.dependencies.serde] +version = "1.0.0" +features = ["derive"] + +[target.'cfg(not(target_family="wasm"))'.dependencies.serde_json] +version = "1.0.0" + +[target.'cfg(not(target_family="wasm"))'.dependencies.soroban-env-host] +version = "=26.1.3" +features = [] + +[target.'cfg(not(target_family="wasm"))'.dependencies.soroban-ledger-snapshot] +version = "26.0.1" +optional = true + +[target.'cfg(not(target_family="wasm"))'.dependencies.stellar-strkey] +version = "=0.0.16" + +[target.'cfg(target_family="wasm")'.dependencies.soroban-env-guest] +version = "=26.1.3" diff --git a/temp_sdk/soroban-sdk-26.0.1/Cargo.toml.orig b/temp_sdk/soroban-sdk-26.0.1/Cargo.toml.orig new file mode 100644 index 0000000..dec4203 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/Cargo.toml.orig @@ -0,0 +1,83 @@ +[package] +name = "soroban-sdk" +description = "Soroban SDK." +homepage = "https://github.com/stellar/rs-soroban-sdk" +repository = "https://github.com/stellar/rs-soroban-sdk" +authors = ["Stellar Development Foundation "] +readme = "README.md" +license = "Apache-2.0" +version.workspace = true +edition = "2021" +rust-version.workspace = true + +exclude = ["test_snapshots/", "src/tests/"] + +[lib] +doctest = false + +[build-dependencies] +rustc_version = "0.4.1" +crate-git-revision = "0.0.6" + +[dependencies] +soroban-sdk-macros = { workspace = true } +stellar-strkey = { workspace = true } +bytes-lit = "0.0.5" +visibility = "0.1.1" + +[target.'cfg(target_family="wasm")'.dependencies] +soroban-env-guest = { workspace = true } + +[target.'cfg(not(target_family="wasm"))'.dependencies] +soroban-env-host = { workspace = true, features = [] } +soroban-ledger-snapshot = { workspace = true, optional = true } +stellar-strkey = { workspace = true } +arbitrary = { version = "~1.3.0", features = ["derive"], optional = true } +derive_arbitrary = { version = "~1.3.0", optional = true } +serde = { version = "1.0.0", features = ["derive"] } +serde_json = "1.0.0" +ed25519-dalek = { version = "2.1.1", features = ["rand_core"], optional = true } +curve25519-dalek = { version = "4.1.3", features = ["digest"], optional = true } +# match the version of rand used in dalek +rand = "0.8.5" +ctor = { version = "0.5.0", optional = true } + +[dev-dependencies] +soroban-sdk-macros = { workspace = true, features = ["testutils"] } +soroban-env-host = { workspace = true, features = ["testutils"] } +soroban-ledger-snapshot = { workspace = true, features = ["testutils"] } +stellar-xdr = { workspace = true, features = ["curr", "std"] } +soroban-spec = { workspace = true } +ed25519-dalek = "2.0.0" +rand = "0.8.5" +ctor = "0.5.0" +hex = "0.4.3" +arbitrary = { version = "~1.3.0", features = ["derive"] } +derive_arbitrary = { version = "~1.3.0" } +proptest = "1.2.0" +proptest-arbitrary-interop = "0.1.0" +libfuzzer-sys = "0.4.7" +expect-test = "1.4.1" +sha2 = "0.10.7" +ark-bn254 = { version = "0.5", default-features = false, features = ["curve"] } +ark-bls12-381 = { version = "0.5", default-features = false, features = ["curve"] } +ark-ff = { version = "0.5", default-features = false } + +[features] +alloc = [] +testutils = ["soroban-sdk-macros/testutils", "soroban-env-host/testutils", "soroban-ledger-snapshot/testutils", "dep:ed25519-dalek", "dep:arbitrary", "dep:derive_arbitrary", "dep:ctor", "dep:soroban-ledger-snapshot"] +experimental_spec_shaking_v2 = ["soroban-sdk-macros/experimental_spec_shaking_v2"] +docs = [] + +# Umbrella feature that enables all hazmat sub-features (backwards compatible) +hazmat = [ + "hazmat-crypto", + "hazmat-address", +] + +# Granular hazmat features +hazmat-crypto = [] +hazmat-address = [] + +[package.metadata.docs.rs] +all-features = true diff --git a/temp_sdk/soroban-sdk-26.0.1/README.md b/temp_sdk/soroban-sdk-26.0.1/README.md new file mode 100644 index 0000000..c26e797 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/README.md @@ -0,0 +1,60 @@ +Soroban SDK supports writing smart contracts for the Wasm-powered [Soroban] smart contract +runtime, deployed on [Stellar]. + +### Docs + +See [developers.stellar.org] for documentation about building smart contracts for [Stellar]. + +[developers.stellar.org]: https://developers.stellar.org +[Stellar]: https://stellar.org +[Soroban]: https://stellar.org/soroban + +### Support + +The two most recent soroban-sdk major releases are supported with critical security fixes. +Critical security issues may be backported to earlier versions if practical, but not guaranteed. +General bugs are only fixed on, and new features are only added to, the latest major release. + +### Features + +See [_features] for a list of all Cargo features and what they do. + +### Migrating Major Versions + +See [_migrating] for a summary of how to migrate from one major version to another. + +### Examples + +```rust +use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; + +#[contract] +pub struct Contract; + +#[contractimpl] +impl Contract { + pub fn hello(env: Env, to: Symbol) -> Vec { + vec![&env, symbol_short!("Hello"), to] + } +} + +#[test] +fn test() { +# } +# #[cfg(feature = "testutils")] +# fn main() { + let env = Env::default(); + let contract_id = env.register(Contract, ()); + let client = ContractClient::new(&env, &contract_id); + + let words = client.hello(&symbol_short!("Dev")); + + assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); +} +# #[cfg(not(feature = "testutils"))] +# fn main() { } +``` + +More examples are available at: +- +- diff --git a/temp_sdk/soroban-sdk-26.0.1/build.rs b/temp_sdk/soroban-sdk-26.0.1/build.rs new file mode 100644 index 0000000..110d333 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/build.rs @@ -0,0 +1,50 @@ +pub fn main() { + // Inform the compiler that the soroban_sdk_internal_no_rssdkver_meta cfg is valid. + // The cfg is used when building the test vectors in this repository, to disable the embedding + // of the rssdkver meta to increase the stability of the build wasms and therefore their wasm + // hash. + println!("cargo::rustc-check-cfg=cfg(soroban_sdk_internal_no_rssdkver_meta)"); + + // Check if we're building for wasm32-unknown-unknown target (cross-compilation safe) + if std::env::var("CARGO_CFG_TARGET_FAMILY").as_deref() == Ok("wasm") + && std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("unknown") + { + if let Ok(version) = rustc_version::version() { + if version.major == 1 && version.minor >= 82 { + panic!("Rust compiler 1.82+ with target 'wasm32-unknown-unknown' is unsupported by the Soroban Environment, use 'wasm32v1-none' available with Rust 1.84+. The 'wasm32-unknown-unknown' target in Rust 1.82+ has features enabled that are not yet supported and not easily disabled: reference-types, multi-value. If you must build for the 'wasm32-unknown-unknown' use Rust 1.81 or earlier."); + } + } + } + + if let Ok(rustc_version) = rustc_version::version() { + println!("cargo:rustc-env=RUSTC_VERSION={rustc_version}"); + } + + // When the experimental_spec_shaking_v2 feature is enabled on a wasm target, check for an + // env var from the build system (Stellar CLI) that indicates it supports spec optimization + // using markers. + if std::env::var("CARGO_FEATURE_EXPERIMENTAL_SPEC_SHAKING_V2").is_ok() { + let env_name = "SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2"; + println!("cargo::rerun-if-env-changed={env_name}"); + if std::env::var(env_name).is_err() + && std::env::var("CARGO_CFG_TARGET_FAMILY").unwrap_or_default() == "wasm" + { + eprintln!( + "\ +\nerror: soroban-sdk feature 'experimental_spec_shaking_v2' requires stellar-cli v25.2.0+\ +\n\ +\nThe soroban-sdk 'experimental_spec_shaking_v2' feature requires building\ +\nwith `stellar contract build` from stellar-cli v25.2.0 or newer.\ +\n\ +\nTo fix, either:\ +\n - Build with `stellar contract build` using stellar-cli v25.2.0+\ +\n - Disable the feature by removing 'experimental_spec_shaking_v2' from\ +\n the soroban-sdk import features list in Cargo.toml.\ +" + ); + std::process::exit(1); + } + } + + crate_git_revision::init(); +} diff --git a/temp_sdk/soroban-sdk-26.0.1/docs/README.md b/temp_sdk/soroban-sdk-26.0.1/docs/README.md new file mode 100644 index 0000000..a310233 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/docs/README.md @@ -0,0 +1,7 @@ +# Soroban SDK Internals Documentation + +This directory contains documentation about the internal workings of the Soroban SDK. It is intended for SDK developers who need to understand or modify the SDK implementation. + +## Contents + +- [contracttrait.md](contracttrait.md) - How the `#[contracttrait]` macro works internally diff --git a/temp_sdk/soroban-sdk-26.0.1/docs/contracttrait.md b/temp_sdk/soroban-sdk-26.0.1/docs/contracttrait.md new file mode 100644 index 0000000..065a758 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/docs/contracttrait.md @@ -0,0 +1,156 @@ +# `#[contracttrait]` Macro Internals + +This document describes how the `#[contracttrait]` macro works internally. It is intended for SDK developers who need to understand or modify the macro implementation. + +## Overview + +The `#[contracttrait]` macro enables defining reusable contract interfaces as Rust traits. When a contract implements such a trait with `#[contractimpl(contracttrait)]`, the macro system generates all the necessary machinery: specs, exported functions, client methods, args variants, and test hooks. + +The key challenge is handling **default trait functions**. When a trait has functions with default implementations, those defaults should be exported unless the contract explicitly overrides them. This requires a multi-stage macro expansion because proc macros cannot see which trait functions are not being overridden at the time they process the trait definition. + +## Diagram + +```mermaid +flowchart TB + subgraph trait_def ["Trait Definer"] + direction TB + A["#91;contracttrait#93;
trait Pause #123;
 // fn without impl
 fn f1#40;...#41;;
 // fn with default impl
 fn f2#40;...#41; #123; ... #125;
#125;"] + style A text-align:left + A -->|generates| B["#91;contractspecfn#93;
trait Pause #123;"] + A -->|generates| C["#91;contractargs#93;
trait Pause #123;"] + A -->|generates| D["#91;contractclient#93;
trait Pause #123;"] + A -->|1. generates| E["#91;contractimpl_trait_macro#93;
trait Pause #123;"] + E -->|2. generates| F["macro_rules! Pause #123;
 #40;impl_fns#41; => #123;
contractimpl_trait_default_fns_not_overridden!#40;
  trait_default_fns = #91;f2#93;,
  impl_fns = $impl_fns,
#41;
 #125;
#125;"] + style F text-align:left + F -->|4. generates| I["contractimpl_trait_default_fns_not_overridden!#40;trait_default_fns, impl_fns#41;"] + end + + subgraph impl_def ["Trait Implementer"] + direction BT + G["#91;contractimpl#40;contracttrait#41;#93;
impl Pause for Contract #123;
 fn f1#40;...#41; #123; ... #125;
#125;"] + style G text-align:left + end + + G -->|"3. calls
Pause!#40;impl_fns = #91;f1#93;#41;"| F + + subgraph outputs ["Generated Code"] + direction BT + J[specs] + K[exported fns] + L[client] + M[args] + N[test hooks] + end + + G -->|generates for impl fns| outputs + I -->|5. generates for default fns not impl| outputs +``` + +## Stage-by-Stage Breakdown + +### Stage 1: `#[contracttrait]` generates helper attributes + +**Source:** `soroban-sdk-macros/src/derive_trait.rs` + +When `#[contracttrait]` is applied to a trait, it wraps the trait with four additional attributes: + +```rust +#[contractspecfn(name = "PauseSpec", export = false)] +#[contractargs(name = "PauseArgs")] +#[contractclient(crate_path = soroban_sdk, name = "PauseClient")] +#[contractimpl_trait_macro(crate_path = soroban_sdk)] +trait Pause { ... } +``` + +Each attribute processes the trait and passes it through to the next, and generates code for a specific purpose. + +The rest of this document focuses on the behavior of the `contractimpl_trait_macro` and how it hooks up to the `contractimpl` macro. + +### Stage 2: `#[contractimpl_trait_macro]` generates a trait macro + +**Source:** `soroban-sdk-macros/src/derive_contractimpl_trait_macro.rs` + +This attribute generates a declarative macro named after the trait (e.g., `Pause!`). The macro is named the same as the trait so that it is automatically imported when the trait is imported, since they share the same namespace. The macro captures all trait functions that have default implementations: + +```rust +#[doc(hidden)] +#[macro_export] +macro_rules! __contractimpl_for_pause { + (/* ... */, $impl_fns:expr, /* ... */) => { + soroban_sdk::contractimpl_trait_default_fns_not_overridden!( + trait_default_fns = ["#[doc(...)] fn f2(_)"], + impl_fns = $impl_fns, + //... + ); + } +} +pub use __contractimpl_for_pause as Pause; +``` + +The `trait_default_fns` contains stringified signatures (and documentation) of all functions with default implementations. We serialize function signatures and their documentation into strings because the tooling used to parse macros and values doesn't handle raw tokens well as parameters. This information is "remembered" by the declarative macro for later comparison. + +### Stage 3: `#[contractimpl(contracttrait)]` calls the trait macro + +**Source:** `soroban-sdk-macros/src/lib.rs:268-280` + +When a contract implements the trait with `contracttrait = true`: + +```rust +#[contractimpl(contracttrait)] +impl Pause for Contract { + fn f1() { ... } +} +``` + +The `contractimpl` macro: +1. Processes the impl block normally (generating specs, client, etc. for implemented functions like `f1`) +2. If the attribute `contracttrait` is included, knows that it should call the trait's macro `Pause!` +3. Generates a call to the `Pause!` macro with the list of implemented function names + +```rust +Pause!( + Contract, + ["f1"], + //... +); +``` + +### Stage 4: The trait macro calls `contractimpl_trait_default_fns_not_overridden` + +The `Pause!` macro expands to call the proc macro `contractimpl_trait_default_fns_not_overridden!` with both: +- `trait_default_fns` - all trait functions with defaults (captured at Stage 2) +- `impl_fns` - functions actually implemented in the impl block (from Stage 3) + +### Stage 5: Generate code for non-overridden default functions + +**Source:** `soroban-sdk-macros/src/derive_contractimpl_trait_default_fns_not_overridden.rs` + +This proc macro: +1. Filters out any functions that appear in `impl_fns` (they're overridden and will already be handled by the `contractimpl` macro like any other implemented non-trait function) +2. For remaining functions (defaults not overridden), generates all the same things that `contractimpl` generates: + - **Specs:** Contract specification entries via `derive_fns_spec` + - **Exported functions:** The actual `__fn_name` exports via `derive_pub_fns` that become the functions in the Wasm file + - **Client methods:** Methods on the client struct via `derive_client_impl` + - **Args variants:** Enum variants for function arguments via `derive_args_impl` + - **Test hooks:** Function registration for test environment via `derive_contract_function_registration_ctor` + +## Why the `macro_rules!` Bridge? + +The two-stage approach with a declarative macro bridge is necessary because: + +1. **Proc macros can't see across items:** When `#[contractimpl]` runs, it can't access the original trait definition to know which functions have defaults. + +2. **Information must be captured early:** The trait definition (with default function bodies) is only available when `#[contracttrait]` runs. + +3. **Comparison happens late:** The list of overridden functions is only known when `#[contractimpl]` runs. + +The `macro_rules!` macro acts as a data carrier, embedding the trait's default function information at definition time and making it available at impl time. + +## Source Files + +| File | Purpose | +|------|---------| +| `soroban-sdk-macros/src/derive_trait.rs` | `#[contracttrait]` entry point | +| `soroban-sdk-macros/src/derive_contractimpl_trait_macro.rs` | Generates the `macro_rules!` helper | +| `soroban-sdk-macros/src/derive_contractimpl_trait_default_fns_not_overridden.rs` | Generates code for non-overridden defaults | +| `soroban-sdk-macros/src/lib.rs` | `#[contractimpl]` with `contracttrait` handling | diff --git a/temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md b/temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md new file mode 100644 index 0000000..61ea2ef --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md @@ -0,0 +1,8 @@ +# doctest_fixtures + +Files contained in this directory are used within examples inside docs, i.e. +doctests. + +`contract.wasm` is a copy of `test_add_u64` test contract. + +`contract_with_constructor.wasm` is a copy of `test_constructor` test contract. diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_features.rs b/temp_sdk/soroban-sdk-26.0.1/src/_features.rs new file mode 100644 index 0000000..f009d51 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_features.rs @@ -0,0 +1,141 @@ +//! # Features +//! +//! The SDK provides several Cargo features that enable additional functionality. +//! +//! ## `testutils` +//! +//! Enables test utilities for writing tests that interact with contracts. +//! Required for using [`Env::default()`] in tests, generating test addresses, +//! and other test helpers. Only available for non-Wasm targets. +//! +//! ## `alloc` +//! +//! Enables the [`alloc`][crate::alloc] module, providing access to the global +//! allocator for use in contracts. +//! +//! ## `hazmat-crypto` +//! +//! Exposes low-level cryptographic primitives (e.g. +//! [`CryptoHazmat`][crate::crypto::CryptoHazmat]) that are easy to misuse. +//! Use with care. +//! +//! ## `hazmat-address` +//! +//! Exposes low-level address primitives (e.g. +//! [`Address::to_payload`][crate::Address::to_payload], +//! [`Address::from_payload`][crate::Address::from_payload]) that are easy to +//! misuse. Use with care. +//! +//! ## `experimental_spec_shaking_v2` +//! +//! Enables v2 spec shaking, an improved mechanism for controlling which type, +//! event, and function definitions appear in a contract's spec. +//! +//! ### Spec Shaking v1 (default, no feature flag) +//! +//! - Lib imports (via `contractimport!`): exported +//! - Wasm imports (via `contractimport!`): not exported +//! - `pub` types: exported +//! - Non-`pub` types: not exported +//! - All events: exported +//! - All functions: exported +//! +//! ### Spec Shaking v2 (this feature) +//! +//! - Everything exported (types, events, functions, imports) +//! - Unused entries shaken out using dead code / spec elimination +//! +//! A contract's spec (the `contractspecv0` custom section in the Wasm binary) +//! contains entries for every function, type, and event defined by the contract. +//! When types or events are defined but not actually used at a contract boundary +//! (parameters, return values, error returns, or event publishes), their spec +//! entries are dead weight. Spec shaking removes them. +//! +//! ### How It Works +//! +//! When this feature is enabled, the SDK embeds 14-byte **markers** in the Wasm +//! data section for each exported type and event. A marker consists of a +//! `SpEcV1` magic prefix followed by 8 bytes of a SHA-256 hash of the spec +//! entry's XDR. +//! +//! Markers are placed inside functions that are only called when the type is +//! actually used: +//! - **Function parameters**: marker is triggered when deserializing the input. +//! - **Function return values**: marker is triggered when serializing the output. +//! - **Error returns**: marker is triggered via `Result` serialization. +//! - **Event publishes**: marker is triggered inside the `publish()` call. +//! - **Nested types**: a type's marker function calls the marker functions of +//! its field types, so nested types are transitively marked. +//! - **Container types**: `Vec`, `Map`, `Option`, and `Result` +//! propagate markers to their inner types. +//! +//! The Rust compiler's dead code elimination (DCE) removes markers for types +//! that are never used, while keeping markers for types that are. +//! +//! Post-build tools (e.g. `stellar-cli`) scan the Wasm data section for +//! `SpEcV1` markers, match them against spec entries, and strip any entries +//! without a corresponding marker. +//! +//! ### Changed Behaviour +//! +//! When this feature is enabled the following macros change behaviour: +//! +//! #### [`contracttype`] +//! +//! Without this feature, spec entries are only generated for `pub` types (or +//! when `export = true` is explicitly set). With this feature, spec entries +//! and markers are generated for all types regardless of visibility, unless +//! `export = false` is explicitly set. This ensures all types can participate +//! in spec shaking. +//! +//! #### [`contracterror`] +//! +//! Same as [`contracttype`]: without this feature, spec entries are only +//! generated for `pub` types. With this feature, spec entries and markers are +//! generated for all error enums regardless of visibility, unless +//! `export = false` is explicitly set. +//! +//! #### [`contractevent`] +//! +//! Markers are embedded for all events, allowing post-build tools to strip +//! spec entries for events that are never published at a contract boundary. +//! +//! #### [`contractimport!`] +//! +//! Without this feature, [`contractimport!`] generates imported types with +//! `export = false`. Imported types do not produce spec entries in the +//! importing contract's spec. They are purely local Rust types used for +//! serialization. The importing contract's spec only contains its own function +//! definitions, and callers must look at the imported contract's spec to find +//! the type definitions. +//! +//! With this feature, [`contractimport!`] generates imported types with +//! `export = true`. Imported types produce spec entries and markers in the +//! importing contract, just like locally defined types. This changes the +//! contract's spec to be self-contained — it includes the type definitions for +//! all types used at the contract boundary, regardless of where those types +//! were originally defined. Specifically: +//! +//! - Imported types that are used in the contract's function signatures or +//! events will have their markers survive DCE and their spec entries will be +//! kept after shaking. +//! - Imported types that are **not** used at any contract boundary will have +//! their markers eliminated by DCE and their spec entries will be stripped. +//! +//! This ensures that a contract importing a large interface only includes spec +//! entries for the types it actually uses, while still producing a +//! self-contained spec. +//! +//! ### Build Requirements +//! +//! This feature requires building with `stellar contract build` from +//! `stellar-cli` v25.2.0 or newer. Building a contract for wasm (e.g. with +//! `cargo build --target wasm32v1-none`) will produce a build error unless the +//! `SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2` environment variable is +//! set. The check only fires for wasm targets; native builds (e.g. unit tests) +//! are unaffected. +//! +//! [`contracttype`]: crate::contracttype +//! [`contracterror`]: crate::contracterror +//! [`contractevent`]: crate::contractevent +//! [`contractimport!`]: crate::contractimport diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs new file mode 100644 index 0000000..bb3bb2c --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs @@ -0,0 +1,324 @@ +//! # Migrating from v25 to v26 +//! +//! 1. Add support for [CAP-78: Host functions for performing limited TTL extensions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0078.md). +//! New `extend_ttl_with_limits` methods on [`Persistent`], [`Instance`], and +//! [`Deployer`] provide bounded control over TTL extensions with `min_extension` and +//! `max_extension` parameters. +//! +//! 2. Add support for [CAP-82: Checked 256-bit integer arithmetic host functions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0082.md). +//! New `checked_*` methods on [`U256`] and [`I256`] (`checked_add`, `checked_sub`, +//! `checked_mul`, `checked_div`, `checked_pow`, `checked_rem_euclid`, `checked_shl`, +//! `checked_shr`) return `Option` instead of panicking on overflow. Also adds +//! `min_value` and `max_value` methods on [`U256`] and [`I256`] to fetch the +//! value bounds of each type. +//! +//! 3. Add support for [CAP-80: Host functions for efficient ZK BN254 use cases](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0080.md). +//! [`BN254`] gains scalar field arithmetic (`Fr` `Add`/`Sub`/`Mul` traits, `pow`, `inv`), +//! multi-scalar multiplication (`g1_msm`), and curve validation (`g1_is_on_curve`). +//! [`BLS12381`] gains `g1_is_on_curve` and `g2_is_on_curve`. +//! +//! 4. Add support for [CAP-79: Host functions for muxed address strkey conversions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0079.md). +//! New method [`MuxedAddress::to_strkey`] converts muxed addresses to Stellar strkey format. +//! +//! 5. Add support for [CAP-73: Allow SAC to create G-account balances](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0073.md). +//! Update the [`StellarAssetInterface`] to include the new method [`StellarAssetInterface::trust`]. This method creates +//! an unlimited trustline for the contract's asset, if applicable. +//! +//! [`Persistent`]: crate::storage::Persistent +//! [`Instance`]: crate::storage::Instance +//! [`Deployer`]: crate::deploy::Deployer +//! [`U256`]: crate::U256 +//! [`I256`]: crate::I256 +//! [`MuxedAddress::to_strkey`]: crate::MuxedAddress::to_strkey +//! [`StellarAssetInterface`]: crate::token::StellarAssetInterface +//! [`StellarAssetInterface::trust`]: crate::token::StellarAssetInterface::trust +//! [`BN254`]: crate::crypto::bn254 +//! [`BLS12381`]: crate::crypto::bls12_381 +//! +//! # Migrating from v23 to v25 +//! +//! 1. [`Events::all()` return type changed from `Vec<(Address, Vec, Val)>` to `ContractEvents`][v25_event_testing]. +//! The new type supports the old comparison format, so most code will continue to work. +//! New methods like `filter_by_contract()` and XDR comparison via `to_xdr()` are now available. +//! +//! 2. [BN254 (alt_bn128) elliptic curve support added][v25_bn254]. +//! Access via `env.crypto().bn254()` for G1/G2 point operations and pairing checks. +//! +//! 3. [Poseidon and Poseidon2 permutation functions added][v25_poseidon]. +//! Available via `CryptoHazmat` under the `hazmat-crypto` feature for advanced +//! cryptographic use cases. +//! +//! 4. [`contracttrait` macro added for reusable contract interfaces][v25_contracttrait]. +//! Define traits with default implementations using `#[contracttrait]`, then implement them +//! in contracts using `#[contractimpl(contracttrait)]`. +//! +//! 5. [Resource limit enforcement enabled by default in tests][v25_resource_limits]. +//! `Env::default()` now enforces Mainnet resource limits for contract invocations. +//! Tests will fail if limits are exceeded. This provides early warning of contracts that +//! may be too resource-heavy for Mainnet. If you see test failures after upgrading, +//! use `env.cost_estimate().disable_resource_limits()` to opt-out while optimizing. +//! +//! [v25_contracttrait]: v25_contracttrait +//! [v25_resource_limits]: v25_resource_limits +//! +//! # Migrating from v22 to v23 +//! +//! 1. [`contractevent` replaces `Events::publish`][v23_contractevent] +//! +//! 2. [`MuxedAddress` replaces `Address` as the `to` of the `TokenInterface::transfer`]. +//! This change concerns `soroban-token-sdk` and is documented in detail in +//! `soroban-token-sdk` crate migration guide. +//! +//! 3. [Accessing archived persistent entries in tests no longer results in a panic][v23_archived_testing], +//! automatic restoration is emulated instead. Note, that instance storage is a +//! persistent entry as well. +//! +//! # Migrating from v21 to v22 +//! +//! 1. [`Env::register`] and [`Env::register_at`] replace [`Env::register_contract`] and [`Env::register_contract_wasm`]. +//! +//! [`register`] registers both native contracts previously registered with +//! [`register_contract`] and Wasm contracts previously registered with +//! [`register_contract_wasm`]. It accepts a tuple that is passed to the +//! contracts constructor. Pass `()` if the contract has no constructor. +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, Env}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! // .. +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let address = env.register( +//! Contract, // 👈 👀 The contract being registered, or a Wasm `&[u8]`. +//! (), // 👈 👀 The constructor arguments, or (). +//! ); +//! // .. +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! [`register_at`] registers both native contracts previously registered +//! with [`register_contract`] and Wasm contracts previously registered with +//! [`register_contract_wasm`], and allows setting the address that the +//! contract is registered at. It accepts a tuple that is passed to the +//! contracts constructor. Pass `()` if the contract has no constructor. +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! // .. +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let address = Address::generate(&env); +//! env.register_at( +//! &address, // 👈 👀 The address to register the contract at. +//! Contract, // 👈 👀 The contract being registered, or a Wasm `&[u8]`. +//! (), // 👈 👀 The constructor arguments, or (). +//! ); +//! // .. +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! 2. [`DeployerWithAddress::deploy_v2`] replaces [`DeployerWithAddress::deploy`]. +//! +//! [`deploy_v2`] is the same as [`deploy`], except it accepts a list of +//! arguments to be passed to the contracts constructor that will be called +//! when it is deployed. For deploying existing contracts that do not have +//! constructors, pass `()`. +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, BytesN, Env}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn exec(env: Env, wasm_hash: BytesN<32>) { +//! let salt = [0u8; 32]; +//! let deployer = env.deployer().with_current_contract(salt); +//! // Pass `()` for contracts that have no contstructor, or have a +//! // constructor and require no arguments. Pass arguments in a +//! // tuple if any required. +//! let contract_address = deployer.deploy_v2(wasm_hash, ()); +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let contract_address = env.register(Contract, ()); +//! let contract = ContractClient::new(&env, &contract_address); +//! // Upload the contract code before deploying its instance. +//! const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); +//! let wasm_hash = env.deployer().upload_contract_wasm(WASM); +//! contract.exec(&wasm_hash); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! 2. Deprecated [`fuzz_catch_panic`]. Use [`Env::try_invoke_contract`] and the `try_` client functions instead. +//! +//! The `fuzz_catch_panic` function could be used in fuzz tests to catch a contract panic. Improved behavior can be found by invoking a contract with the `try_` variant of the invoke function contract clients. +//! +//! ``` +//! use libfuzzer_sys::fuzz_target; +//! use soroban_sdk::{contract, contracterror, contractimpl, Env, testutils::arbitrary::*}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contracterror] +//! #[derive(Debug, PartialEq)] +//! pub enum Error { +//! Overflow = 1, +//! } +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn add(x: u32, y: u32) -> Result { +//! x.checked_add(y).ok_or(Error::Overflow) +//! } +//! } +//! +//! #[derive(Arbitrary, Debug)] +//! pub struct Input { +//! pub x: u32, +//! pub y: u32, +//! } +//! +//! fuzz_target!(|input: Input| { +//! let env = Env::default(); +//! let id = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &id); +//! +//! let result = client.try_add(&input.x, &input.y); +//! match result { +//! // Returned if the function succeeds, and the value returned is +//! // the type expected. +//! Ok(Ok(_)) => {} +//! // Returned if the function succeeds, and the value returned is +//! // NOT the type expected. +//! Ok(Err(_)) => panic!("unexpected type"), +//! // Returned if the function fails, and the error returned is +//! // recognised as part of the contract errors enum. +//! Err(Ok(_)) => {} +//! // Returned if the function fails, and the error returned is NOT +//! // recognised, or the contract panic'd. +//! Err(Err(_)) => panic!("unexpected error"), +//! } +//! }); +//! +//! # fn main() { } +//! ``` +//! +//! 3. Events in test snapshots are now reduced to only contract events and system events. Diagnostic events will no longer appear in test snapshots. +//! +//! This will cause all test snapshot JSON files generated by the SDK to change when upgrading to this major version of the SDK. The change should be isolated to events and should omit only diagnostic events. +//! +//! [`Env::register`]: crate::Env::register +//! [`register`]: crate::Env::register +//! [`Env::register_at`]: crate::Env::register_at +//! [`register_at`]: crate::Env::register_at +//! [`Env::register_contract`]: crate::Env::register_contract +//! [`register_contract`]: crate::Env::register_contract +//! [`Env::register_contract_wasm`]: crate::Env::register_contract_wasm +//! [`register_contract_wasm`]: crate::Env::register_contract_wasm +//! [`DeployerWithAddress::deploy_v2`]: crate::deploy::DeployerWithAddress::deploy_v2 +//! [`deploy_v2`]: crate::deploy::DeployerWithAddress::deploy_v2 +//! [`DeployerWithAddress::deploy`]: crate::deploy::DeployerWithAddress::deploy +//! [`deploy`]: crate::deploy::DeployerWithAddress::deploy +//! [`fuzz_catch_panic`]: crate::testutils::arbitrary::fuzz_catch_panic +//! [`Env::try_invoke_contract`]: crate::Env::try_invoke_contract +//! +//! # Migrating from v20 to v21 +//! +//! 1. [`CustomAccountInterface::__check_auth`] function `signature_payload` parameter changes from type [`BytesN<32>`] to [`Hash<32>`]. +//! +//! The two types are ABI-compatible. [`Hash<32>`] contains a [`BytesN<32>`]. +//! For [`CustomAccountInterface::__check_auth`], the host constructs the +//! `signature_payload`, so it is guaranteed to contain bytes produced by the +//! host's authentication payload hash. This guarantee is specific to +//! host-managed `__check_auth` invocations and does not apply to general +//! contract entrypoint arguments. +//! +//! To convert from a [`Hash<32>`] to a [`BytesN<32>`], use [`Hash<32>::to_bytes`] or [`Into::into`]. +//! +//! Current implementations of the interface will see a build error, and should change [`BytesN<32>`] to [`Hash<32>`]. +//! +//! ``` +//! use soroban_sdk::{ +//! auth::{Context, CustomAccountInterface}, contract, +//! contracterror, contractimpl, crypto::Hash, Env, +//! Vec, +//! }; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contracterror] +//! pub enum Error { +//! AnError = 1, +//! // ... +//! } +//! +//! #[contractimpl] +//! impl CustomAccountInterface for Contract { +//! type Signature = (); +//! type Error = Error; +//! +//! fn __check_auth( +//! env: Env, +//! signature_payload: Hash<32>, // 👈 👀 +//! signatures: (), +//! auth_contexts: Vec, +//! ) -> Result<(), Self::Error> { +//! // ... +//! # todo!() +//! } +//! } +//! +//! # fn main() { } +//! ``` +//! +//! [`CustomAccountInterface::__check_auth`]: crate::auth::CustomAccountInterface::__check_auth +//! [`BytesN<32>`]: crate::BytesN +//! [`Hash<32>`]: crate::crypto::Hash +//! [`Hash<32>::to_bytes`]: crate::crypto::Hash::to_bytes + +pub mod v23_archived_testing; +pub mod v23_contractevent; +pub mod v25_bn254; +pub mod v25_contracttrait; +pub mod v25_event_testing; +pub mod v25_poseidon; +pub mod v25_resource_limits; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs new file mode 100644 index 0000000..788b57c --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs @@ -0,0 +1,176 @@ +//! Accessing archived persistent entries in tests no longer results in an error. +//! +//! Prior to protocol 23 the SDK used to emulate the failure when an archived +//! ledger entry was accessed in tests. This behavior has never represented the +//! actual behavior of the network, just one possible scenario when an archived +//! entry is present in the transaction footprint. +//! +//! In protocol 23 automatic entry restoration has been introduced, which makes +//! it possible for a transaction to restore an archived entry before accessing +//! it. As this behavior will become the most common case on the network, the +//! SDK has been changed to emulate automatic restoration in tests as well. +//! +//! Note, that instance storage is a persistent entry as well, so it is subject +//! to the same change. +//! +//! ## Example +//! +//! Consider the following simple contract that extends entry TTL +//! along with the test that relies on the error on archived entry access in +//! SDK 22: +//! +//! ``` +//! #![no_std] +//! use soroban_sdk::{contract, contractimpl, contracttype, Env}; +//! +//! #[contract] +//! struct Contract; +//! +//! #[contracttype] +//! enum DataKey { +//! Key, +//! } +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn create_and_extend_entry(env: Env) { +//! env.storage().persistent().set(&DataKey::Key, &123_u32); +//! // Extend the entry to live for at least 1_000_000 ledgers. +//! env.storage() +//! .persistent() +//! .extend_ttl(&DataKey::Key, 1_000_000, 1_000_000); +//! } +//! +//! pub fn read_entry(env: Env) -> u32 { +//! env.storage().persistent().get(&DataKey::Key).unwrap() +//! } +//! } +//! +//! mod test { +//! extern crate std; +//! use soroban_sdk::testutils::{storage::Persistent, Ledger}; +//! +//! use super::*; +//! +//! #[test] +//! fn test_entry_archived() { +//! let env = Env::default(); +//! let contract = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract); +//! client.create_and_extend_entry(); +//! let current_ledger = env.ledger().sequence(); +//! assert_eq!(client.read_entry(), 123); +//! +//! // Bump ledger sequence past entry TTL. +//! env.ledger() +//! .set_sequence_number(current_ledger + 1_000_000 + 1); +//! let res = client.try_read_entry(); +//! // 👀 In SDK 22 `res` would be an error because the entry is archived. +//! // 👀 In SDK 23 `res` is Ok(123) because the entry is automatically restored. +//! assert!(res.is_err()); +//! } +//! } +//! +//! # fn main() { } +//! ``` +//! +//! The best way to address this change is to update the tests to explicitly +//! verify the expected entry TTL after the extension. This way there is no need +//! to rely on the storage behavior, and also the test becomes more robust as +//! it enforces the exact expected TTL value, so there is no risk of bumping +//! the ledger sequence further than the expected TTL and still having the test +//! pass. +//! +//! The example test above can be re-written as follows: +//! +//! ``` +//! #![no_std] +//! use soroban_sdk::{contract, contractimpl, contracttype, Env}; +//! +//! #[contract] +//! struct Contract; +//! +//! #[contracttype] +//! enum DataKey { +//! Key, +//! } +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn create_and_extend_entry(env: Env) { +//! env.storage().persistent().set(&DataKey::Key, &123_u32); +//! // Extend the entry to live for at least 1_000_000 ledgers. +//! env.storage() +//! .persistent() +//! .extend_ttl(&DataKey::Key, 1_000_000, 1_000_000); +//! } +//! +//! pub fn read_entry(env: Env) -> u32 { +//! env.storage().persistent().get(&DataKey::Key).unwrap() +//! } +//! } +//! +//! #[cfg(test)] +//! mod test { +//! extern crate std; +//! use soroban_sdk::testutils::{storage::Persistent, Ledger}; +//! +//! use super::*; +//! +//! #[test] +//! fn test_entry_ttl_extended() { +//! let env = Env::default(); +//! let contract = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract); +//! client.create_and_extend_entry(); +//! assert_eq!(client.read_entry(), 123); +//! +//! // 👀 Verify that the entry TTL was extended correctly by 1000000 ledgers. +//! env.as_contract(&contract, || { +//! assert_eq!(env.storage().persistent().get_ttl(&DataKey::Key), 1_000_000); +//! }); +//! } +//! +//! // 👀 This test is not really necessary, but it demonstrates the +//! // auto-restoration behavior in tests. +//! #[test] +//! fn test_auto_restore() { +//! let env = Env::default(); +//! let contract = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract); +//! client.create_and_extend_entry(); +//! let current_ledger = env.ledger().sequence(); +//! +//! // Bump ledger sequence past entry TTL. +//! env.ledger() +//! .set_sequence_number(current_ledger + 1_000_000 + 1); +//! // 👀 Entry can still be accessed because automatic restoration is emulated +//! // in tests. +//! assert_eq!(client.read_entry(), 123); +//! +//! // 👀 Automatic restoration is also accounted for in cost_estimate(): +//! let resources = env.cost_estimate().resources(); +//! // Even though `read_entry` call is normally read-only, auto-restoration +//! // will cause 2 entry writes here: 1 for the contract instance, another +//! // one for the restored entry. +//! assert_eq!(resources.write_entries, 2); +//! // 2 rent bumps will happen as well for the respective entries. +//! assert_eq!(resources.persistent_entry_rent_bumps, 2); +//! +//! // 👀 Entry TTL after auto-restoration can be observed via get_ttl(). +//! env.as_contract(&contract, || { +//! // Auto-restored entries have their TTL extended by the minimum +//! // possible TTL worth of ledgers (`min_persistent_entry_ttl`), +//! // including the ledger in which they were restored (that's why +//! // we subtract 1 here). +//! assert_eq!( +//! env.storage().persistent().get_ttl(&DataKey::Key), +//! env.ledger().get().min_persistent_entry_ttl - 1 +//! ); +//! }); +//! } +//! } +//! +//! # fn main() { } +//! ``` +//! diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs new file mode 100644 index 0000000..7e34326 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs @@ -0,0 +1,438 @@ +//! [`contractevent`] replaces [`Events::publish`]. +//! +//! The [`contractevent`] macro provides a type-safe way to define and publish events, and +//! includes the event into the contract interface specification so that tooling, SDKs, and +//! generated clients can understand the events published. +//! +//! ## Example +//! +//! For example, consider the following event publishing code: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123u32; +//! # env.as_contract(&id, || { +//! // Define and publish the event: +//! env.events().publish( +//! // Event topics +//! (symbol_short!("increment"), &addr), +//! // Event data +//! Map::::from_array(&env, [ +//! (symbol_short!("count"), count.into()) +//! ]), +//! ); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("increment"), &addr).into_val(&env), +//! // Event data +//! Map::::from_array(&env, [ +//! (symbol_short!("count"), count.into()) +//! ]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! Replace it with the following code using [`contractevent`]: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123; +//! # env.as_contract(&id, || { +//! // Define the event: +//! #[contractevent] +//! pub struct Increment { +//! #[topic] +//! addr: Address, +//! count: u32, +//! } +//! +//! // Publish the event: +//! Increment { +//! addr: addr.clone(), +//! count: count, +//! }.publish(&env); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("increment"), &addr).into_val(&env), +//! // Event data +//! Map::::from_array(&env, [ +//! (symbol_short!("count"), count.into()) +//! ]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! ## Example: Vec Data +//! +//! By default the parameters not marked as `#[topic]`s are collected into a [`Map`] like in the +//! example above. If transitioning events that publish parameters in a [`Vec`], follow the +//! this example. +//! +//! Consider the following event publishing code: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Address, IntoVal, Vec, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123u32; +//! # env.as_contract(&id, || { +//! // Define and publish the event: +//! env.events().publish( +//! // Event topics +//! (symbol_short!("increment"), &addr), +//! // Event data +//! Vec::::from_array(&env, [count.into()]), +//! ); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("increment"), &addr).into_val(&env), +//! // Event data +//! Vec::::from_array(&env, [count.into()]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! Replace it with the following code using [`contractevent`]: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Vec, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123; +//! # env.as_contract(&id, || { +//! // Define the event: +//! #[contractevent(data_format = "vec")] +//! pub struct Increment { +//! #[topic] +//! addr: Address, +//! count: u32, +//! } +//! +//! // Publish the event: +//! Increment { +//! addr: addr.clone(), +//! count: count, +//! }.publish(&env); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("increment"), &addr).into_val(&env), +//! // Event data +//! Vec::::from_array(&env, [count.into()]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! ## Example: Other Data +//! +//! If transitioning events that publish some other type directly into the event's data field, +//! follow the this example. +//! +//! Consider the following event publishing code: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Address, IntoVal, Vec, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123u32; +//! # env.as_contract(&id, || { +//! // Define and publish the event: +//! env.events().publish( +//! // Event topics +//! (symbol_short!("increment"), &addr), +//! // Event data +//! count, +//! ); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("increment"), &addr).into_val(&env), +//! // Event data +//! count.into(), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! Replace it with the following code using [`contractevent`]: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123; +//! # env.as_contract(&id, || { +//! // Define the event: +//! #[contractevent(data_format = "single-value")] +//! pub struct Increment { +//! #[topic] +//! addr: Address, +//! count: u32, +//! } +//! +//! // Publish the event: +//! Increment { +//! addr: addr.clone(), +//! count: count, +//! }.publish(&env); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("increment"), &addr).into_val(&env), +//! // Event data +//! count.into(), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! ## Example: Customising Topics +//! +//! By default the topics of an event are made up of a single static topic that is the event's name +//! converted to snake_case, along with any dynamic topics specified by `#[topic]` on the field. +//! +//! ### Custom Static Topic +//! +//! The static topic can be changed using the `topics = [...]` option on [`contractevent`]: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123; +//! # env.as_contract(&id, || { +//! #[contractevent(topics = ["count_chn"])] +//! pub struct Increment { +//! #[topic] +//! addr: Address, +//! count: u32, +//! } +//! # +//! # Increment { +//! # addr: addr.clone(), +//! # count: count, +//! # }.publish(&env); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("count_chn"), &addr,).into_val(&env), +//! // Event data +//! Map::::from_array(&env, [ +//! (symbol_short!("count"), count.into()) +//! ]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! ### Multiple Static Topics +//! +//! Multiple static topics can be set using the `topics = [...]` option on [`contractevent`], with +//! up to two values: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123; +//! # env.as_contract(&id, || { +//! #[contractevent(topics = ["count", "increment"])] +//! pub struct Increment { +//! #[topic] +//! addr: Address, +//! count: u32, +//! } +//! # +//! # Increment { +//! # addr: addr.clone(), +//! # count: count, +//! # }.publish(&env); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (symbol_short!("count"), symbol_short!("increment"), &addr,).into_val(&env), +//! // Event data +//! Map::::from_array(&env, [ +//! (symbol_short!("count"), count.into()) +//! ]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! ### No Static Topics +//! +//! Zero static topics can be specified with the following configuration where `topics = []` is +//! provided to [`contractevent`]: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # let addr = Address::generate(&env); +//! # let count = 123; +//! # env.as_contract(&id, || { +//! #[contractevent(topics = [])] +//! pub struct Increment { +//! #[topic] +//! addr: Address, +//! count: u32, +//! } +//! # +//! # Increment { +//! # addr: addr.clone(), +//! # count: count, +//! # }.publish(&env); +//! # }); +//! +//! // Assert in tests on the published topics and data: +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! // Event topics +//! (&addr,).into_val(&env), +//! // Event data +//! Map::::from_array(&env, [ +//! (symbol_short!("count"), count.into()) +//! ]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! [`Events::publish`]: crate::events::Events::publish +//! [`Address`]: crate::MuxedAddress +//! [`MuxedAddress`]: crate::MuxedAddress +//! [`contractevent`]: crate::contractevent +//! [`Map`]: crate::Map diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs new file mode 100644 index 0000000..4fb7a3e --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs @@ -0,0 +1,138 @@ +//! BN254 (alt_bn128) elliptic curve support. +//! +//! Support for BN254 (also known as alt_bn128), a pairing-friendly elliptic curve commonly used in +//! zero-knowledge proof systems. +//! +//! The BN254 functionality is accessed via `env.crypto().bn254()`. +//! +//! ## New Types +//! +//! - [`Bn254G1Affine`] - A point in the G1 group (64 bytes, Ethereum-compatible format) +//! - [`Bn254G2Affine`] - A point in the G2 group (128 bytes, Ethereum-compatible format) +//! - [`Bn254Fr`] - A scalar field element (32 bytes, internally a `U256`) +//! - [`Bn254Fp`] - A base field element (32 bytes) +//! +//! ## New Operations +//! +//! - `g1_add` - Add two G1 points +//! - `g1_mul` - Multiply a G1 point by a scalar +//! - `pairing_check` - Multi-pairing check for ZK proof verification +//! +//! G1 points also support arithmetic operations via Rust traits: +//! - `Add` - Add two G1 points +//! - `Mul` - Multiply a G1 point by a scalar +//! - `Neg` - Negate a G1 point +//! +//! ## Example: Basic G1 Operations +//! +//! ``` +//! use soroban_sdk::{Env, BytesN, U256}; +//! use soroban_sdk::crypto::bn254::{Bn254Fr, Bn254G1Affine}; +//! +//! # fn main() { +//! let env = Env::default(); +//! let bn254 = env.crypto().bn254(); +//! +//! // The generator point G1 for BN254 +//! // G1 = (1, 2) +//! let g1_bytes: [u8; 64] = [ +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // x = 1 +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, // y = 2 +//! ]; +//! let g1 = Bn254G1Affine::from_array(&env, &g1_bytes); +//! +//! // Add the generator to itself: G + G = 2G +//! let g1_doubled = bn254.g1_add(&g1, &g1); +//! +//! // Or use the Add trait +//! let g1_doubled_alt = g1.clone() + g1.clone(); +//! assert_eq!(g1_doubled, g1_doubled_alt); +//! +//! // Scalar multiplication: 2 * G should equal G + G +//! let scalar: Bn254Fr = U256::from_u32(&env, 2).into(); +//! let g1_times_2 = bn254.g1_mul(&g1, &scalar); +//! assert_eq!(g1_doubled, g1_times_2); +//! +//! // Or use the Mul trait +//! let g1_times_2_alt = g1.clone() * scalar; +//! assert_eq!(g1_doubled, g1_times_2_alt); +//! # } +//! ``` +//! +//! ## Example: Point Negation +//! +//! ``` +//! use soroban_sdk::{Env, BytesN}; +//! use soroban_sdk::crypto::bn254::Bn254G1Affine; +//! +//! # fn main() { +//! let env = Env::default(); +//! let bn254 = env.crypto().bn254(); +//! +//! // G1 generator point (1, 2) +//! let g1_bytes: [u8; 64] = [ +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, +//! ]; +//! let g1 = Bn254G1Affine::from_array(&env, &g1_bytes); +//! +//! // Negate the point: -G has same x but negated y +//! let neg_g1 = -g1.clone(); +//! +//! // G + (-G) = point at infinity (all zeros) +//! let sum = bn254.g1_add(&g1, &neg_g1); +//! let infinity = Bn254G1Affine::from_array(&env, &[0u8; 64]); +//! assert_eq!(sum, infinity); +//! # } +//! ``` +//! +//! ## Example: Pairing Check +//! +//! ``` +//! use soroban_sdk::{Env, vec, Vec}; +//! use soroban_sdk::crypto::bn254::{Bn254G1Affine, Bn254G2Affine}; +//! +//! # fn main() { +//! let env = Env::default(); +//! let bn254 = env.crypto().bn254(); +//! +//! // Example G1 and G2 points from Ethereum test vectors - https://github.com/ethereum/go-ethereum/blob/master/core/vm/testdata/precompiles/bn256Pairing.json +//! let g1_bytes: [u8; 64] = [ +//! 0x1c, 0x76, 0x47, 0x6f, 0x4d, 0xef, 0x4b, 0xb9, 0x45, 0x41, 0xd5, 0x7e, 0xbb, 0xa1, 0x19, 0x33, +//! 0x81, 0xff, 0xa7, 0xaa, 0x76, 0xad, 0xa6, 0x64, 0xdd, 0x31, 0xc1, 0x60, 0x24, 0xc4, 0x3f, 0x59, +//! 0x30, 0x34, 0xdd, 0x29, 0x20, 0xf6, 0x73, 0xe2, 0x04, 0xfe, 0xe2, 0x81, 0x1c, 0x67, 0x87, 0x45, +//! 0xfc, 0x81, 0x9b, 0x55, 0xd3, 0xe9, 0xd2, 0x94, 0xe4, 0x5c, 0x9b, 0x03, 0xa7, 0x6a, 0xef, 0x41, +//! ]; +//! let g1 = Bn254G1Affine::from_array(&env, &g1_bytes); +//! +//! let g2_bytes: [u8; 128] = [ +//! 0x20, 0x9d, 0xd1, 0x5e, 0xbf, 0xf5, 0xd4, 0x6c, 0x4b, 0xd8, 0x88, 0xe5, 0x1a, 0x93, 0xcf, 0x99, +//! 0xa7, 0x32, 0x96, 0x36, 0xc6, 0x35, 0x14, 0x39, 0x6b, 0x4a, 0x45, 0x20, 0x03, 0xa3, 0x5b, 0xf7, +//! 0x04, 0xbf, 0x11, 0xca, 0x01, 0x48, 0x3b, 0xfa, 0x8b, 0x34, 0xb4, 0x35, 0x61, 0x84, 0x8d, 0x28, +//! 0x90, 0x59, 0x60, 0x11, 0x4c, 0x8a, 0xc0, 0x40, 0x49, 0xaf, 0x4b, 0x63, 0x15, 0xa4, 0x16, 0x78, +//! 0x2b, 0xb8, 0x32, 0x4a, 0xf6, 0xcf, 0xc9, 0x35, 0x37, 0xa2, 0xad, 0x1a, 0x44, 0x5c, 0xfd, 0x0c, +//! 0xa2, 0xa7, 0x1a, 0xcd, 0x7a, 0xc4, 0x1f, 0xad, 0xbf, 0x93, 0x3c, 0x2a, 0x51, 0xbe, 0x34, 0x4d, +//! 0x12, 0x0a, 0x2a, 0x4c, 0xf3, 0x0c, 0x1b, 0xf9, 0x84, 0x5f, 0x20, 0xc6, 0xfe, 0x39, 0xe0, 0x7e, +//! 0xa2, 0xcc, 0xe6, 0x1f, 0x0c, 0x9b, 0xb0, 0x48, 0x16, 0x5f, 0xe5, 0xe4, 0xde, 0x87, 0x75, 0x50, +//! ]; +//! let g2 = Bn254G2Affine::from_array(&env, &g2_bytes); +//! +//! // Create vectors of G1 and G2 points +//! let g1_vec: Vec = vec![&env, g1]; +//! let g2_vec: Vec = vec![&env, g2]; +//! +//! // Perform pairing check +//! // Returns true if e(G1[0], G2[0]) * e(G1[1], G2[1]) * ... = 1 +//! let result = bn254.pairing_check(g1_vec, g2_vec); +//! // result will be true or false depending on the pairing equation +//! # } +//! ``` +//! +//! [`Bn254G1Affine`]: crate::crypto::bn254::Bn254G1Affine +//! [`Bn254G2Affine`]: crate::crypto::bn254::Bn254G2Affine +//! [`Bn254Fr`]: crate::crypto::bn254::Bn254Fr +//! [`Bn254Fp`]: crate::crypto::bn254::Bn254Fp diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs new file mode 100644 index 0000000..6be0777 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs @@ -0,0 +1,335 @@ +//! [`contracttrait`] macro for reusable contract interfaces. +//! +//! _Note: This feature was released in v23.4.0 but is being included in the migration notes for the +//! next major version, v25._ +//! +//! The [`contracttrait`] macro enables defining reusable contract interfaces as Rust traits with +//! default implementations. Contracts can implement these traits, and the default implementations +//! are automatically exported as contract functions. +//! +//! ## Generated Functionality +//! +//! When applied to a trait, [`contracttrait`] generates: +//! +//! - `{TraitName}Client` - A client for invoking the trait's functions on a contract +//! - `{TraitName}Args` - An enum of function arguments for the trait's functions +//! - `{TraitName}Spec` - The contract specification for the trait's functions +//! +//! These names can be customized using macro arguments (e.g., `client_name`, `args_name`, +//! `spec_name`). +//! +//! ## When to Use +//! +//! Use [`contracttrait`] when you want the trait to represent a contract interface. +//! +//! The [`contracttrait`] will make it possible to: +//! - Access a generated client for any contract implementing the interface. +//! - Automatically export default implementations that contracts can optionally override +//! - Share common functionality across contracts +//! +//! ## How It Works +//! +//! 1. **Define a trait** with [`contracttrait`] +//! +//! 2. **Implement the trait** with [`contractimpl`], including the `contracttrait` option: +//! `#[contractimpl(contracttrait)]` +//! +//! 3. **Override default functions as needed** - Contracts can provide their own implementations of +//! any function with default implementations. +//! +//! ## Patterns For Use +//! +//! Place traits that use [`contracttrait`] into a library crate, to share and make those traits +//! available to other crates and developers. +//! +//! [`contracttrait`]: crate::contracttrait +//! [`contractimpl`]: crate::contractimpl +//! +//! ## Example: Defining and Implementing a Trait +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; +//! +//! // A regular trait for admin access control - not exported as contract functions +//! pub trait RequireAuthForPause { +//! fn require_auth_for_pause(env: &Env); +//! } +//! +//! // Define a contracttrait with default implementations that require RequireAuthForPause +//! #[contracttrait] +//! pub trait Pausable: RequireAuthForPause { +//! fn is_paused(env: &Env) -> bool { +//! env.storage().instance().has(&"paused") +//! } +//! +//! fn pause(env: &Env) { +//! Self::require_auth_for_pause(env); +//! env.storage().instance().set(&"paused", &true); +//! } +//! +//! fn unpause(env: &Env) { +//! Self::require_auth_for_pause(env); +//! env.storage().instance().remove(&"paused"); +//! } +//! } +//! +//! #[contract] +//! pub struct MyContract; +//! +//! impl RequireAuthForPause for MyContract { +//! fn require_auth_for_pause(env: &Env) { +//! let admin: Address = env.storage().instance().get(&"admin").unwrap(); +//! admin.require_auth(); +//! } +//! } +//! +//! // Implement the trait - default functions are automatically exported +//! #[contractimpl(contracttrait)] +//! impl Pausable for MyContract {} +//! +//! #[contractimpl] +//! impl MyContract { +//! pub fn __constructor(env: &Env, admin: Address) { +//! env.storage().instance().set(&"admin", &admin); +//! } +//! +//! pub fn do_something(env: &Env) { +//! if Self::is_paused(env) { +//! panic!("contract is paused"); +//! } +//! // ... rest of the function +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! use soroban_sdk::{testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; +//! let env = Env::default(); +//! let admin = Address::generate(&env); +//! let contract_id = env.register(MyContract, (&admin,)); +//! let client = PausableClient::new(&env, &contract_id); +//! +//! assert!(!client.is_paused()); +//! client.mock_auths(&[MockAuth { +//! address: &admin, +//! invoke: &MockAuthInvoke { +//! contract: &contract_id, +//! fn_name: "pause", +//! args: ().into_val(&env), +//! sub_invokes: &[], +//! }, +//! }]).pause(); +//! assert!(client.is_paused()); +//! client.mock_auths(&[MockAuth { +//! address: &admin, +//! invoke: &MockAuthInvoke { +//! contract: &contract_id, +//! fn_name: "unpause", +//! args: ().into_val(&env), +//! sub_invokes: &[], +//! }, +//! }]).unpause(); +//! assert!(!client.is_paused()); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! ## Example: Overriding Default Implementations +//! +//! Contracts can override specific functions while keeping the defaults for others: +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; +//! +//! // A regular trait for admin access control - not exported as contract functions +//! pub trait RequireAuthForPause { +//! fn require_auth_for_pause(env: &Env); +//! } +//! +//! // Define a contracttrait with default implementations that require RequireAuthForPause +//! #[contracttrait] +//! pub trait Pausable: RequireAuthForPause { +//! fn is_paused(env: &Env) -> bool { +//! env.storage().instance().has(&"paused") +//! } +//! +//! fn pause(env: &Env) { +//! Self::require_auth_for_pause(env); +//! env.storage().instance().set(&"paused", &true); +//! } +//! +//! fn unpause(env: &Env) { +//! Self::require_auth_for_pause(env); +//! env.storage().instance().remove(&"paused"); +//! } +//! } +//! +//! #[contract] +//! pub struct MyContract; +//! +//! impl RequireAuthForPause for MyContract { +//! fn require_auth_for_pause(env: &Env) { +//! let admin: Address = env.storage().instance().get(&"admin").unwrap(); +//! admin.require_auth(); +//! } +//! } +//! +//! // Implement the trait - override default implementations as needed +//! #[contractimpl(contracttrait)] +//! impl Pausable for MyContract { +//! // Override is_paused with custom logic that returns false when not set +//! fn is_paused(env: &Env) -> bool { +//! env.storage().instance().get(&"paused").unwrap_or(false) +//! } +//! // pause() and unpause() use the default implementations +//! } +//! +//! #[contractimpl] +//! impl MyContract { +//! pub fn __constructor(env: &Env, admin: Address) { +//! env.storage().instance().set(&"admin", &admin); +//! } +//! +//! pub fn do_something(env: &Env) { +//! if Self::is_paused(env) { +//! panic!("contract is paused"); +//! } +//! // ... rest of the function +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! use soroban_sdk::{testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; +//! let env = Env::default(); +//! let admin = Address::generate(&env); +//! let contract_id = env.register(MyContract, (&admin,)); +//! let client = PausableClient::new(&env, &contract_id); +//! +//! assert!(!client.is_paused()); +//! client.mock_auths(&[MockAuth { +//! address: &admin, +//! invoke: &MockAuthInvoke { +//! contract: &contract_id, +//! fn_name: "pause", +//! args: ().into_val(&env), +//! sub_invokes: &[], +//! }, +//! }]).pause(); +//! assert!(client.is_paused()); +//! client.mock_auths(&[MockAuth { +//! address: &admin, +//! invoke: &MockAuthInvoke { +//! contract: &contract_id, +//! fn_name: "unpause", +//! args: ().into_val(&env), +//! sub_invokes: &[], +//! }, +//! }]).unpause(); +//! assert!(!client.is_paused()); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! ## Example: Using the Generated Client +//! +//! The generated `{TraitName}Client` can be used to call any contract that implements the trait: +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; +//! +//! // A regular trait for admin access control - not exported as contract functions +//! pub trait RequireAuthForPause { +//! fn require_auth_for_pause(env: &Env); +//! } +//! +//! // Define a contracttrait with default implementations that require RequireAuthForPause +//! #[contracttrait] +//! pub trait Pausable: RequireAuthForPause { +//! fn is_paused(env: &Env) -> bool { +//! env.storage().instance().has(&"paused") +//! } +//! +//! fn pause(env: &Env) { +//! Self::require_auth_for_pause(env); +//! env.storage().instance().set(&"paused", &true); +//! } +//! +//! fn unpause(env: &Env) { +//! Self::require_auth_for_pause(env); +//! env.storage().instance().remove(&"paused"); +//! } +//! } +//! +//! #[contract] +//! pub struct MyContract; +//! +//! impl RequireAuthForPause for MyContract { +//! fn require_auth_for_pause(env: &Env) { +//! let admin: Address = env.storage().instance().get(&"admin").unwrap(); +//! admin.require_auth(); +//! } +//! } +//! +//! // Implement the trait - default functions are automatically exported +//! #[contractimpl(contracttrait)] +//! impl Pausable for MyContract {} +//! +//! #[contractimpl] +//! impl MyContract { +//! pub fn __constructor(env: &Env, admin: Address) { +//! env.storage().instance().set(&"admin", &admin); +//! } +//! +//! pub fn do_something(env: &Env) { +//! if Self::is_paused(env) { +//! panic!("contract is paused"); +//! } +//! // ... rest of the function +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! use soroban_sdk::{testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; +//! let env = Env::default(); +//! let admin = Address::generate(&env); +//! let contract_id = env.register(MyContract, (&admin,)); +//! let client = PausableClient::new(&env, &contract_id); +//! +//! assert!(!client.is_paused()); +//! client.mock_auths(&[MockAuth { +//! address: &admin, +//! invoke: &MockAuthInvoke { +//! contract: &contract_id, +//! fn_name: "pause", +//! args: ().into_val(&env), +//! sub_invokes: &[], +//! }, +//! }]).pause(); +//! assert!(client.is_paused()); +//! client.mock_auths(&[MockAuth { +//! address: &admin, +//! invoke: &MockAuthInvoke { +//! contract: &contract_id, +//! fn_name: "unpause", +//! args: ().into_val(&env), +//! sub_invokes: &[], +//! }, +//! }]).unpause(); +//! assert!(!client.is_paused()); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs new file mode 100644 index 0000000..613cc04 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs @@ -0,0 +1,154 @@ +//! `Events::all()` return type changed from `Vec<(Address, Vec, Val)>` to [`ContractEvents`]. +//! +//! The [`ContractEvents`] struct provides a more ergonomic interface for asserting on +//! emitted events. It can be compared directly with: +//! - `[xdr::ContractEvent; _]` +//! - `std::vec::Vec` +//! - `Vec<(Address, Vec, Val)>` (maintains backward compatibility with the old format) +//! +//! The [`ContractEvents`] struct also provides utility methods: +//! - `filter_by_contract` - filter events by contract address +//! - `events` - get the underlying XDR events +//! +//! Additionally, events defined with [`contractevent`] now have a `to_xdr` method available with +//! `testutils` feature that converts the event to its XDR representation for comparison. +//! +//! ## Example: Using the old comparison style +//! +//! The old comparison style using `Vec<(Address, Vec, Val)>` still works: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Symbol, Val, testutils::{Address as _, Events as _}}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # env.as_contract(&id, || { +//! #[contractevent] +//! pub struct MyEvent { +//! #[topic] +//! name: Symbol, +//! value: u32, +//! } +//! +//! MyEvent { +//! name: symbol_short!("hello"), +//! value: 42, +//! }.publish(&env); +//! # }); +//! +//! // The old comparison style still works: +//! use soroban_sdk::Map; +//! assert_eq!( +//! env.events().all(), +//! vec![&env, +//! ( +//! id.clone(), +//! (symbol_short!("my_event"), symbol_short!("hello")).into_val(&env), +//! Map::::from_array(&env, [ +//! (symbol_short!("value"), 42u32.into()) +//! ]).into_val(&env), +//! ), +//! ] +//! ); +//! # } +//! ``` +//! +//! ## Example: Using XDR comparison (new recommended style) +//! +//! The new style uses `to_xdr` on the event for cleaner assertions: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Symbol, Val, testutils::{Address as _, Events as _}, Event}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let id = env.register(Contract, ()); +//! # +//! #[contractevent] +//! pub struct MyEvent { +//! #[topic] +//! name: Symbol, +//! value: u32, +//! } +//! +//! let event = MyEvent { +//! name: symbol_short!("hello"), +//! value: 42, +//! }; +//! +//! # env.as_contract(&id, || { +//! event.publish(&env); +//! # }); +//! +//! // New style: compare with XDR directly +//! assert_eq!( +//! env.events().all(), +//! std::vec![event.to_xdr(&env, &id)], +//! ); +//! # } +//! ``` +//! +//! ## Example: Filtering events by contract +//! +//! Use `filter_by_contract` to get events from a specific contract: +//! +//! ``` +//! # #![cfg(feature = "testutils")] +//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Symbol, Val, testutils::{Address as _, Events as _}, Event}; +//! # +//! # #[contract] +//! # pub struct Contract; +//! # +//! # fn main() { +//! # let env = Env::default(); +//! # let contract_a = env.register(Contract, ()); +//! # let contract_b = env.register(Contract, ()); +//! # +//! #[contractevent] +//! pub struct MyEvent { +//! #[topic] +//! name: Symbol, +//! value: u32, +//! } +//! +//! let event_a = MyEvent { +//! name: symbol_short!("hello"), +//! value: 1, +//! }; +//! let event_b = MyEvent { +//! name: symbol_short!("world"), +//! value: 2, +//! }; +//! +//! env.as_contract(&contract_a, || { +//! event_a.publish(&env); +//! env.as_contract(&contract_b, || { +//! event_b.publish(&env); +//! }); +//! }); +//! +//! // Filter to get only events from contract_a +//! assert_eq!( +//! env.events().all().filter_by_contract(&contract_a), +//! std::vec![event_a.to_xdr(&env, &contract_a)], +//! ); +//! +//! // Filter to get only events from contract_b +//! assert_eq!( +//! env.events().all().filter_by_contract(&contract_b), +//! std::vec![event_b.to_xdr(&env, &contract_b)], +//! ); +//! # } +//! ``` +//! +//! [`ContractEvents`]: crate::testutils::ContractEvents +//! [`contractevent`]: crate::contractevent diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs new file mode 100644 index 0000000..d0a802c --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs @@ -0,0 +1,100 @@ +//! Poseidon and Poseidon2 permutation functions. +//! +//! Protocol 25 exposes low-level Poseidon and Poseidon2 permutation host functions +//! for advanced cryptographic use cases. These are available through the `CryptoHazmat` +//! interface under the `hazmat-crypto` feature. +//! +//! Higher level non-hazmat functionality will be released in a separate crate. +//! +//! ## ⚠️ Hazardous Materials Warning +//! +//! These are low-level cryptographic primitives. Most users should use higher-level +//! constructions built on top of these permutations. Incorrect usage can lead to +//! security vulnerabilities. +//! +//! ## Enabling the Feature +//! +//! Add the `hazmat-crypto` feature to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! soroban-sdk = { version = "25", features = ["hazmat-crypto"] } +//! ``` +//! +//! ## Poseidon Permutation +//! +//! The `poseidon_permutation` function performs the standard Poseidon permutation +//! with a full MDS matrix. +//! +//! Parameters: +//! - `input` - State vector of `U256` field elements +//! - `field` - Field identifier (e.g., `"BN254"`) +//! - `t` - State width (number of elements) +//! - `d` - S-box exponent (typically 5) +//! - `rounds_f` - Number of full rounds (must be even) +//! - `rounds_p` - Number of partial rounds +//! - `mds` - MDS matrix (`t × t` matrix of `U256` elements) +//! - `round_constants` - Round constants (one vector per round) +//! +//! ## Poseidon2 Permutation +//! +//! The `poseidon2_permutation` function performs the Poseidon2 permutation with an +//! optimized internal matrix representation. +//! +//! Parameters: +//! - `input` - State vector of `U256` field elements +//! - `field` - Field identifier (e.g., `"BN254"`) +//! - `t` - State width (number of elements) +//! - `d` - S-box exponent (typically 5) +//! - `rounds_f` - Number of full rounds (must be even) +//! - `rounds_p` - Number of partial rounds +//! - `mat_internal_diag_m_1` - Diagonal of internal matrix minus identity +//! - `round_constants` - Round constants (one vector per round) +//! +//! ## Example +//! +//! ```ignore +//! use soroban_sdk::{bytesn, vec, Env, Symbol, U256}; +//! use soroban_sdk::crypto::CryptoHazmat; +//! +//! # fn main() { +//! let env = Env::default(); +//! +//! // Define MDS matrix (2x2 for t=2) +//! let mds = vec![ +//! &env, +//! vec![&env, +//! U256::from_be_bytes(&env, &bytesn!(&env, 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5).into()), +//! U256::from_be_bytes(&env, &bytesn!(&env, 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8).into()), +//! ], +//! vec![&env, +//! U256::from_be_bytes(&env, &bytesn!(&env, 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9).into()), +//! U256::from_be_bytes(&env, &bytesn!(&env, 0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8).into()), +//! ], +//! ]; +//! +//! // Define round constants +//! let rc = vec![ +//! &env, +//! vec![&env, U256::from_u32(&env, 1), U256::from_u32(&env, 2)], +//! vec![&env, U256::from_u32(&env, 3), U256::from_u32(&env, 4)], +//! vec![&env, U256::from_u32(&env, 5), U256::from_u32(&env, 6)], +//! ]; +//! +//! let input = vec![&env, U256::from_u32(&env, 0), U256::from_u32(&env, 1)]; +//! +//! let hazmat = CryptoHazmat::new(&env); +//! let result = hazmat.poseidon_permutation( +//! &input, +//! Symbol::new(&env, "BN254"), +//! 2, // t: state width +//! 5, // d: s-box exponent +//! 2, // rounds_f: full rounds +//! 1, // rounds_p: partial rounds +//! &mds, +//! &rc, +//! ); +//! +//! assert_eq!(result.len(), 2); +//! # } +//! ``` diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs new file mode 100644 index 0000000..fe3eda8 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs @@ -0,0 +1,145 @@ +//! Resource limit enforcement in tests. +//! +//! ## Breaking Change: Tests May Fail Due to Resource Limits +//! +//! By default, [`Env::default()`] now enforces mainnet resource limits for contract invocations in +//! tests. **If your contract exceeds any resource limit, your tests will panic** with details +//! about which limits were exceeded. +//! +//! This provides an early warning that a contract might be too resource-heavy to run on mainnet. +//! +//! **If you see test failures after upgrading**, and you wish to test without mainnet limits +//! (e.g., while experimenting or optimizing), see [Disabling Resource +//! Limits](#disabling-resource-limits) below. +//! +//! ## New Default Behavior +//! +//! When creating a new `Env` with [`Env::default()`], mainnet resource limits are automatically +//! enforced. No changes to existing test code are required to benefit from this protection. +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, Env}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn execute() { +//! // ... code +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); // Mainnet limits enforced automatically +//! let contract_id = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract_id); +//! client.execute(); // Will panic if resource limit exceeded +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! ## Disabling Resource Limits +//! +//! For experimental contracts that are still being optimized, resource limit enforcement can be +//! disabled using [`CostEstimate::disable_resource_limits()`]: +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, Env}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn execute() { +//! // ... resource-heavy code +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! env.cost_estimate().disable_resource_limits(); // Disable resource limit +//! +//! let contract_id = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract_id); +//! client.execute(); // Won't panic even if limits exceeded +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! ## Custom Resource Limits +//! +//! Custom resource limits can be enforced using [`CostEstimate::enforce_resource_limits()`]: +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, Env}; +//! use soroban_sdk::testutils::cost_estimate::NetworkInvocationResourceLimits; +//! use soroban_env_host::InvocationResourceLimits; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn execute() { +//! // ... code +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! +//! // Use custom limits (this example uses mainnet limits as a base) +//! let mut limits = InvocationResourceLimits::mainnet(); +//! limits.instructions = 100_000_000; // Reduce instruction limit +//! env.cost_estimate().enforce_resource_limits(limits); +//! +//! let contract_id = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract_id); +//! client.execute(); // Uses the custom limits +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! ## Mainnet Resource Limits +//! +//! The [`NetworkInvocationResourceLimits`] trait provides the `mainnet()` method on +//! [`InvocationResourceLimits`] to get the current mainnet limits: +//! +//! - Instructions: 600,000,000 +//! - Memory: 41,943,040 bytes +//! - Disk read entries: 100 +//! - Write entries: 50 +//! - Ledger entries: 100 +//! - Disk read bytes: 200,000 +//! - Write bytes: 132,096 +//! - Contract events size: 16,384 bytes +//! - Max contract data key size: 250 bytes +//! - Max contract data entry size: 65,536 bytes +//! - Max contract code entry size: 131,072 bytes +//! +//! Note: These values are not pulled dynamically. The SDK will be updated from time-to-time to +//! pick up changes to mainnet limits. These changes may occur in any major, minor, or patch +//! release. +//! +//! [`Env::default()`]: crate::Env::default +//! [`CostEstimate::disable_resource_limits()`]: crate::testutils::cost_estimate::CostEstimate::disable_resource_limits +//! [`CostEstimate::enforce_resource_limits()`]: crate::testutils::cost_estimate::CostEstimate::enforce_resource_limits +//! [`InvocationResourceLimits`]: soroban_env_host::InvocationResourceLimits +//! [`NetworkInvocationResourceLimits`]: crate::testutils::cost_estimate::NetworkInvocationResourceLimits diff --git a/temp_sdk/soroban-sdk-26.0.1/src/address.rs b/temp_sdk/soroban-sdk-26.0.1/src/address.rs new file mode 100644 index 0000000..9522a0b --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/address.rs @@ -0,0 +1,450 @@ +use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; + +use super::{ + contracttype, env::internal::AddressObject, env::internal::Env as _, unwrap::UnwrapInfallible, + Bytes, BytesN, ConversionError, Env, IntoVal, String, TryFromVal, TryIntoVal, Val, Vec, +}; + +#[cfg(any(test, feature = "hazmat-address"))] +use crate::address_payload::AddressPayload; + +#[cfg(not(target_family = "wasm"))] +use crate::env::internal::xdr::{AccountId, ScVal}; +#[cfg(any(test, feature = "testutils", not(target_family = "wasm")))] +use crate::env::xdr::ScAddress; + +/// Address is a universal opaque identifier to use in contracts. +/// +/// Address can be used as an input argument (for example, to identify the +/// payment recipient), as a data key (for example, to store the balance), as +/// the authentication & authorization source (for example, to authorize the +/// token transfer) etc. +/// +/// See `require_auth` documentation for more details on using Address for +/// authorization. +/// +/// Internally, Address may represent a Stellar account or a contract. Contract +/// address may be used to identify the account contracts - special contracts +/// that allow customizing authentication logic and adding custom authorization +/// rules. +/// +/// In tests Addresses should be generated via `Address::generate()`. +#[derive(Clone)] +pub struct Address { + env: Env, + obj: AddressObject, +} + +impl Debug for Address { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(target_family = "wasm")] + write!(f, "Address(..)")?; + #[cfg(not(target_family = "wasm"))] + { + use crate::env::internal::xdr; + use stellar_strkey::{ed25519, Contract, Strkey}; + let sc_val = ScVal::try_from(self).map_err(|_| core::fmt::Error)?; + if let ScVal::Address(addr) = sc_val { + match addr { + xdr::ScAddress::Account(account_id) => { + let xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256( + ed25519, + ))) = account_id; + let strkey = Strkey::PublicKeyEd25519(ed25519::PublicKey(ed25519)); + write!(f, "AccountId({})", strkey.to_string())?; + } + xdr::ScAddress::Contract(xdr::ContractId(contract_id)) => { + let strkey = Strkey::Contract(Contract(contract_id.0)); + write!(f, "Contract({})", strkey.to_string())?; + } + ScAddress::MuxedAccount(_) + | ScAddress::ClaimableBalance(_) + | ScAddress::LiquidityPool(_) => { + return Err(core::fmt::Error); + } + } + } else { + return Err(core::fmt::Error); + } + } + Ok(()) + } +} + +impl Eq for Address {} + +impl PartialEq for Address { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for Address { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Address { + fn cmp(&self, other: &Self) -> Ordering { + #[cfg(not(target_family = "wasm"))] + if !self.env.is_same_env(&other.env) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = self + .env + .obj_cmp(self.obj.to_val(), other.obj.to_val()) + .unwrap_infallible(); + v.cmp(&0) + } +} + +impl TryFromVal for Address { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &AddressObject) -> Result { + Ok(unsafe { Address::unchecked_new(env.clone(), *val) }) + } +} + +impl TryFromVal for Address { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(AddressObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &Address) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&Address) -> Result { + Ok(v.to_val()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Address> for ScVal { + fn from(v: &Address) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From
for ScVal { + fn from(v: Address) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Address { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok( + AddressObject::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible(), + ) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Address> for ScAddress { + fn from(v: &Address) -> Self { + match ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() { + ScVal::Address(a) => a, + _ => panic!("expected ScVal::Address"), + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl From
for ScAddress { + fn from(v: Address) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Address { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScAddress) -> Result { + Ok(AddressObject::try_from_val( + env, + &Val::try_from_val(env, &ScVal::Address(val.clone()))?, + )? + .try_into_val(env) + .unwrap_infallible()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFrom<&Address> for AccountId { + type Error = ConversionError; + fn try_from(v: &Address) -> Result { + let sc: ScAddress = v.into(); + match sc { + ScAddress::Account(aid) => Ok(aid), + _ => Err(ConversionError), + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFrom
for AccountId { + type Error = ConversionError; + fn try_from(v: Address) -> Result { + (&v).try_into() + } +} + +#[contracttype(crate_path = "crate", export = false)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Executable { + Wasm(BytesN<32>), + StellarAsset, + Account, +} + +impl Address { + /// Ensures that this Address has authorized invocation of the current + /// contract with the provided arguments. + /// + /// During the on-chain execution the Soroban host will perform the needed + /// authentication (verify the signatures) and ensure the replay prevention. + /// The contracts don't need to perform this tasks. + /// + /// The arguments don't have to match the arguments of the contract + /// invocation. However, it's considered the best practice to have a + /// well-defined, deterministic and ledger-state-independent mapping between + /// the contract invocation arguments and `require_auth` arguments. This + /// will allow the contract callers to easily build the required signature + /// payloads and prevent potential authorization failures. + /// + /// ### Panics + /// + /// If the invocation is not authorized. + pub fn require_auth_for_args(&self, args: Vec) { + self.env.require_auth_for_args(self, args); + } + + /// Ensures that this Address has authorized invocation of the current + /// contract with all the invocation arguments + /// + /// This works exactly in the same fashion as `require_auth_for_args`, but + /// arguments are automatically inferred from the current contract + /// invocation. + /// + /// This is useful when there is only a single Address that needs to + /// authorize the contract invocation and there are no dynamic arguments + /// that don't need authorization. + /// + /// ### Panics + /// + /// If the invocation is not authorized. + pub fn require_auth(&self) { + self.env.require_auth(self); + } + + /// Creates an `Address` corresponding to the provided Stellar strkey. + /// + /// The only supported strkey types are account keys (`G...`) and contract keys (`C...`). Any + /// other valid or invalid strkey will cause this to panic. + /// + /// Prefer using the `Address` directly as input or output argument. Only + /// use this in special cases when addresses need to be shared between + /// different environments (e.g. different chains). + pub fn from_str(env: &Env, strkey: &str) -> Address { + Address::from_string(&String::from_str(env, strkey)) + } + + /// Creates an `Address` corresponding to the provided Stellar strkey. + /// + /// The only supported strkey types are account keys (`G...`) and contract keys (`C...`). Any + /// other valid or invalid strkey will cause this to panic. + /// + /// Prefer using the `Address` directly as input or output argument. Only + /// use this in special cases when addresses need to be shared between + /// different environments (e.g. different chains). + pub fn from_string(strkey: &String) -> Self { + let env = strkey.env(); + unsafe { + Self::unchecked_new( + env.clone(), + env.strkey_to_address(strkey.to_object().to_val()) + .unwrap_infallible(), + ) + } + } + + /// Creates an `Address` corresponding to the provided Stellar strkey bytes. + /// + /// This behaves exactly in the same fashion as `from_strkey`, i.e. the bytes should contain + /// exactly the same contents as `String` would (i.e. base-32 ASCII string). + /// + /// The only supported strkey types are account keys (`G...`) and contract keys (`C...`). Any + /// other valid or invalid strkey will cause this to panic. + /// + /// Prefer using the `Address` directly as input or output argument. Only + /// use this in special cases when addresses need to be shared between + /// different environments (e.g. different chains). + pub fn from_string_bytes(strkey: &Bytes) -> Self { + let env = strkey.env(); + unsafe { + Self::unchecked_new( + env.clone(), + env.strkey_to_address(strkey.to_object().to_val()) + .unwrap_infallible(), + ) + } + } + + /// Returns the executable type of this address, if any. + /// + /// Returns None when the contract or account does not exist. + /// + /// For Wasm contracts, this also returns the hash of the contract code. + /// Otherwise, this just returns which kind of 'built-in' executable this is + /// (StellarAsset or Account). + pub fn executable(&self) -> Option { + let executable_val: Val = + Env::get_address_executable(&self.env, self.obj).unwrap_infallible(); + executable_val.into_val(&self.env) + } + + /// Returns whether this address exists in the ledger. + /// + /// For the contract addresses, this means that there is a corresponding + /// contract instance deployed. For account addresses, this means that the + /// account entry exists in the ledger. + pub fn exists(&self) -> bool { + let executable_val: Val = + Env::get_address_executable(&self.env, self.obj).unwrap_infallible(); + !executable_val.is_void() + } + + /// Converts this `Address` into the corresponding Stellar strkey. + pub fn to_string(&self) -> String { + String::try_from_val( + &self.env, + &self.env.address_to_strkey(self.obj).unwrap_infallible(), + ) + .unwrap_optimized() + } + + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: AddressObject) -> Self { + Self { env, obj } + } + + #[inline(always)] + pub fn env(&self) -> &Env { + &self.env + } + + pub fn as_val(&self) -> &Val { + self.obj.as_val() + } + + pub fn to_val(&self) -> Val { + self.obj.to_val() + } + + pub fn as_object(&self) -> &AddressObject { + &self.obj + } + + pub fn to_object(&self) -> AddressObject { + self.obj + } + + /// Extracts the payload from the address. + /// + /// Returns: + /// - For contract addresses (C...), returns [`AddressPayload::ContractIdHash`] + /// containing the 32-byte contract hash. + /// - For account addresses (G...), returns [`AddressPayload::AccountIdPublicKeyEd25519`] + /// containing the 32-byte Ed25519 public key. + /// + /// Returns `None` if the address type is not recognized. This may occur if + /// a new address type has been introduced to the network that this version + /// of this library is not aware of. + /// + /// # Warning + /// + /// For account addresses, the returned Ed25519 public key corresponds to + /// the account's master key, which depending on the configuration of that + /// account may or may not be a signer of the account. Do not use this for + /// custom Ed25519 signature verification as a form of authentication + /// because the master key may not be configured the signer of the account. + #[cfg(any(test, feature = "hazmat-address"))] + #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))] + pub fn to_payload(&self) -> Option { + AddressPayload::from_address(self) + } + + /// Constructs an [`Address`] from an [`AddressPayload`]. + /// + /// This is the inverse of [`to_payload`][Address::to_payload]. + /// + /// # Warning + /// + /// For account addresses, the returned Ed25519 public key corresponds to + /// the account's master key, which depending on the configuration of that + /// account may or may not be a signer of the account. Do not use this for + /// custom Ed25519 signature verification as a form of authentication + /// because the master key may not be configured the signer of the account. + #[cfg(any(test, feature = "hazmat-address"))] + #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))] + pub fn from_payload(env: &Env, payload: AddressPayload) -> Address { + payload.to_address(env) + } +} + +#[cfg(any(not(target_family = "wasm"), test, feature = "testutils"))] +use crate::env::xdr::{ContractId, Hash}; +use crate::unwrap::UnwrapOptimized; + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl crate::testutils::Address for Address { + fn generate(env: &Env) -> Self { + Self::try_from_val( + env, + &ScAddress::Contract(ContractId(Hash(env.with_generator(|mut g| g.address())))), + ) + .unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl Address { + pub(crate) fn contract_id(&self) -> ContractId { + let sc_address: ScAddress = self.try_into().unwrap(); + if let ScAddress::Contract(c) = sc_address { + c + } else { + panic!("address is not a contract {:?}", self); + } + } + + pub(crate) fn from_contract_id(env: &Env, contract_id: [u8; 32]) -> Self { + Self::try_from_val(env, &ScAddress::Contract(ContractId(Hash(contract_id)))).unwrap() + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs b/temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs new file mode 100644 index 0000000..e0ca0ed --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs @@ -0,0 +1,126 @@ +#![cfg(any(test, feature = "hazmat-address"))] +#![cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))] + +//! Address payload extraction and construction. +//! +//! This module provides types and functions for extracting raw payloads from +//! addresses and constructing addresses from raw payloads. This is useful for +//! cross-chain interoperability where raw addresses need to be passed between +//! different systems. +//! +//! # Warning +//! +//! For account addresses, the returned Ed25519 public key corresponds to +//! the account's master key, which depending on the configuration of that +//! account may or may not be a signer of the account. Do not use this for +//! custom Ed25519 signature verification as a form of authentication +//! because the master key may not be configured the signer of the account. + +use crate::{unwrap::UnwrapOptimized, Address, Bytes, BytesN, Env}; + +/// The payload contained in an [`Address`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum AddressPayload { + /// A 32-byte Ed25519 public key from an account address (G...). + /// + /// # Warning + /// + /// The Ed25519 public key corresponds to the account's master key, which + /// depending on the configuration of that account may or may not be a + /// signer of the account. Do not use this for custom Ed25519 signature + /// verification as a form of authentication. + AccountIdPublicKeyEd25519(BytesN<32>), + /// A 32-byte contract hash from a contract address (C...). + ContractIdHash(BytesN<32>), +} + +impl AddressPayload { + /// Constructs an [`Address`] from this payload. + /// + /// This is the inverse of [`from_address`][AddressPayload::from_address]. + /// + /// # Warning + /// + /// For account addresses, the returned Ed25519 public key corresponds to + /// the account's master key, which depending on the configuration of that + /// account may or may not be a signer of the account. Do not use this for + /// custom Ed25519 signature verification as a form of authentication + /// because the master key may not be configured the signer of the account. + pub fn to_address(&self, env: &Env) -> Address { + use crate::xdr::FromXdr; + // Build XDR header and get payload bytes based on payload type: + let (header, payload_bytes) = match self { + AddressPayload::AccountIdPublicKeyEd25519(bytes) => ( + [ + 0, 0, 0, 18, // ScVal::Address + 0, 0, 0, 0, // ScAddress::Account + 0, 0, 0, 0, // PublicKey::PublicKeyTypeEd25519 + ] + .as_slice(), + bytes.as_bytes(), + ), + AddressPayload::ContractIdHash(bytes) => ( + [ + 0, 0, 0, 18, // ScVal::Address + 0, 0, 0, 1, // ScAddress::Contract + ] + .as_slice(), + bytes.as_bytes(), + ), + }; + + let mut xdr = Bytes::from_slice(env, header); + xdr.append(payload_bytes); + + Address::from_xdr(env, &xdr).unwrap_optimized() + } + + /// Extracts an [`AddressPayload`] from an [`Address`]. + /// + /// Returns: + /// - For contract addresses (C...), returns [`AddressPayload::ContractIdHash`] + /// containing the 32-byte contract hash. + /// - For account addresses (G...), returns [`AddressPayload::AccountIdPublicKeyEd25519`] + /// containing the 32-byte Ed25519 public key. + /// + /// Returns `None` if the address type is not recognized. This may occur if + /// a new address type has been introduced to the network that this version + /// of this library is not aware of. + /// + /// # Warning + /// + /// For account addresses, the returned Ed25519 public key corresponds to + /// the account's master key, which depending on the configuration of that + /// account may or may not be a signer of the account. Do not use this for + /// custom Ed25519 signature verification as a form of authentication + /// because the master key may not be configured the signer of the account. + pub fn from_address(address: &Address) -> Option { + use crate::xdr::ToXdr; + let xdr = address.to_xdr(address.env()); + // Skip over ScVal discriminant because we know it is an ScAddress. + let xdr = xdr.slice(4..); + // Decode ScAddress + let addr_type: BytesN<4> = xdr.slice(0..4).try_into().unwrap_optimized(); + match addr_type.to_array() { + // Decode ScAddress::Account + [0, 0, 0, 0] => { + // Decode PublicKey + let public_key_type: BytesN<4> = xdr.slice(4..8).try_into().unwrap_optimized(); + match public_key_type.to_array() { + // Decode PublicKey::PublicKeyTypeEd25519 + [0, 0, 0, 0] => { + let ed25519: BytesN<32> = xdr.slice(8..40).try_into().unwrap_optimized(); + Some(AddressPayload::AccountIdPublicKeyEd25519(ed25519)) + } + _ => None, + } + } + // Decode ScAddress::Contract + [0, 0, 0, 1] => { + let hash: BytesN<32> = xdr.slice(4..36).try_into().unwrap_optimized(); + Some(AddressPayload::ContractIdHash(hash)) + } + _ => None, + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs b/temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs new file mode 100644 index 0000000..bd9b0bb --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs @@ -0,0 +1,122 @@ +// This code is adapted from https://github.com/wenyuzhao/bump-allocator-rs +// +// We've altered it to work entirely with usize values internally and only cast +// back to an exposed-provenance pointer when returning from alloc. This gives +// us a richer checked-arithmetic API we can use to trap overflows internally, +// and also avoids some potential UB issues with pointer provenance. Since the +// provenance of __heap_base is a 1-byte value anyway, and all the rest of the +// wasm heap is considered to have exposed provenance, we think this is the best +// we can do. Writing allocators is tricky! +// +// NB: technically these alterations only handle corner cases that cannot be hit +// using safe client code. Safe clients pass `Layout` structs that always meet +// additional size and alignment constraints. But hardening the code to tolerate +// even _unsafe_ inputs -- malformed `Layout` inputs one can only create by +// calling unsafe methods -- is not only easy to do, it makes the code simpler +// and more readable, so we went ahead and did it. + +use crate::unwrap::UnwrapOptimized; +use core::alloc::{GlobalAlloc, Layout}; + +#[global_allocator] +static GLOBAL: BumpPointer = BumpPointer; + +struct BumpPointer; + +// Safety: The mutable reference to LOCAL_ALLOCATOR in GlobalAlloc::alloc is +// safe because: +// +// 1. This code only runs on wasm32, which is single-threaded — no concurrent +// access is possible. +// 2. The reference is narrowly scoped — it is created, used for a single +// method call, and immediately dropped within GlobalAlloc::alloc. +// 3. Reentrancy cannot occur — none of the code called through +// BumpPointerLocal::alloc can allocate (it is all simple integer +// arithmetic and wasm intrinsics), so the global allocator will not +// be re-entered while the reference is live. +// +// See: https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html#safe-references +static mut LOCAL_ALLOCATOR: BumpPointerLocal = BumpPointerLocal::new(); + +unsafe impl GlobalAlloc for BumpPointer { + #[inline(always)] + #[allow(static_mut_refs)] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let (bytes, align) = (layout.size(), layout.align()); + let ptr = LOCAL_ALLOCATOR.alloc(bytes, align); + core::ptr::with_exposed_provenance_mut(ptr) + } + + // No-op. See the module-level documentation on `crate::alloc` for details. + #[inline(always)] + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +} + +struct BumpPointerLocal { + cursor: usize, + limit: usize, +} + +impl BumpPointerLocal { + const LOG_PAGE_SIZE: usize = 16; + const PAGE_SIZE: usize = 1 << Self::LOG_PAGE_SIZE; // 64KB + const MEM: u32 = 0; // Memory 0 is the only legal one currently + + pub const fn new() -> Self { + Self { + cursor: 0, + limit: 0, + } + } + + #[inline(always)] + fn maybe_init_inline(&mut self) { + if self.limit == 0 { + // This is a slight over-estimate and ideally we would use __heap_base + // but that seems not to be easy to access and in any case it is just a + // convention whereas this is more guaranteed by the wasm spec to work. + self.cursor = core::arch::wasm32::memory_size(Self::MEM) + .checked_mul(Self::PAGE_SIZE) + .unwrap_optimized(); + self.limit = self.cursor; + } + } + + #[inline(never)] + fn maybe_init(&mut self) { + self.maybe_init_inline() + } + + // Allocate `bytes` bytes with `align` alignment. + #[inline(always)] + fn alloc(&mut self, bytes: usize, align: usize) -> usize { + self.maybe_init(); + let start = self + .cursor + .checked_next_multiple_of(align) + .unwrap_optimized(); + let new_cursor = start.checked_add(bytes).unwrap_optimized(); + if new_cursor <= self.limit { + self.cursor = new_cursor; + start + } else { + self.alloc_slow(bytes, align) + } + } + + #[inline(always)] + fn alloc_slow_inline(&mut self, bytes: usize, align: usize) -> usize { + let pages = bytes.div_ceil(Self::PAGE_SIZE); + if core::arch::wasm32::memory_grow(Self::MEM, pages) == usize::MAX { + core::arch::wasm32::unreachable(); + } + let bytes_grown = pages.checked_mul(Self::PAGE_SIZE).unwrap_optimized(); + self.limit = self.limit.checked_add(bytes_grown).unwrap_optimized(); + self.alloc(bytes, align) + } + + #[inline(never)] + fn alloc_slow(&mut self, bytes: usize, align: usize) -> usize { + self.alloc_slow_inline(bytes, align) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs b/temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs new file mode 100644 index 0000000..eff6be1 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs @@ -0,0 +1,61 @@ +//! Allocator used by contracts built with the `alloc` feature. +//! +//! The `alloc` feature is **disabled by default**. It exists to support a +//! use-case that is both expensive (in terms of CPU time and code size) and +//! typically unnecessary: allocating unbounded memory, dynamically, in the wasm +//! guest's linear-memory heap. Soroban was designed to avoid this need most of +//! the time: host objects like [`Vec`](crate::Vec), [`Map`](crate::Map), or +//! [`Bytes`](crate::Bytes) already support dynamic growth, but live in the host +//! heap and are efficient to use from the guest without any guest memory +//! allocator. Moreover even if a contract _does_ want guest-memory storage of +//! dynamic data, it can accomplish it in bounded static memory using a crate +//! like [`heapless`](https://crates.io/crates/heapless). Turning on the `alloc` +//! feature should usually be the last choice for contracts with no better +//! option. +//! +//! # Enabling +//! +//! Add the `alloc` feature to `soroban-sdk` in your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! soroban-sdk = { version = "...", features = ["alloc"] } +//! ``` +//! +//! With the feature enabled the SDK registers a global bump-pointer allocator +//! that services all allocations made through Rust's [`alloc`](alloc_crate) +//! APIs. This makes heap-allocated types such as `::alloc::vec::Vec` and +//! `::alloc::string::String` available inside contracts, and enables SDK helpers +//! that require allocation (e.g. [`Bytes::to_alloc_vec`]). +//! +//! [alloc_crate]: https://doc.rust-lang.org/alloc/ +//! [`Bytes::to_alloc_vec`]: crate::Bytes::to_alloc_vec +//! +//! # Using a Custom Allocator +//! +//! The bump-pointer allocator provided by the `alloc` feature is just one +//! possible implementation. A contract is free to define its own global +//! allocator by implementing [`GlobalAlloc`] and registering it with the +//! [`#[global_allocator]`](macro@global_allocator) attribute. See the +//! [Rust `GlobalAlloc` documentation][global_alloc_docs] for details. +//! +//! If you supply your own allocator there is no need to enable the `alloc` +//! feature. +//! +//! [`GlobalAlloc`]: core::alloc::GlobalAlloc +//! [global_alloc_docs]: https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html +//! +//! # How the `alloc` Allocator Works +//! +//! The `alloc` allocator is a simple bump-pointer (arena) allocator. Each call to +//! `alloc` advances a cursor through Wasm linear memory, growing the memory as +//! needed. **`dealloc` is a no-op** — memory is never freed during contract +//! execution. All allocations made during an invocation persist until the host +//! destroys the VM instance at the end of the invocation. +//! +//! This design is a good fit for Soroban contracts because each invocation runs +//! to completion and then the entire VM is discarded. There is no long-lived +//! process that would benefit from returning memory to the allocator. + +#[cfg(target_family = "wasm")] +mod bump_pointer; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs b/temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs new file mode 100644 index 0000000..9e05794 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs @@ -0,0 +1,71 @@ +//! Extra trait impls required by the bounds to `SorobanArbitrary`. +//! +//! These are in their own module so that they are defined even when "testutils" +//! is not configured, making type inference consistent between configurations. + +use crate::ConversionError; +use crate::Error; +use crate::{Env, TryFromVal}; + +impl TryFromVal for u32 { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &u32) -> Result { + Ok(*v) + } +} + +impl TryFromVal for i32 { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &i32) -> Result { + Ok(*v) + } +} + +impl TryFromVal for u64 { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &u64) -> Result { + Ok(*v) + } +} + +impl TryFromVal for i64 { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &i64) -> Result { + Ok(*v) + } +} + +impl TryFromVal for u128 { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &u128) -> Result { + Ok(*v) + } +} + +impl TryFromVal for i128 { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &i128) -> Result { + Ok(*v) + } +} + +impl TryFromVal for bool { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &bool) -> Result { + Ok(*v) + } +} + +impl TryFromVal for () { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &()) -> Result { + Ok(*v) + } +} + +impl TryFromVal for Error { + type Error = ConversionError; + fn try_from_val(_env: &Env, v: &Error) -> Result { + Ok(*v) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/auth.rs b/temp_sdk/soroban-sdk-26.0.1/src/auth.rs new file mode 100644 index 0000000..035d514 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/auth.rs @@ -0,0 +1,108 @@ +//! Auth contains types for building custom account contracts. + +use crate::{ + contractimpl_trait_macro, contracttype, crypto::Hash, Address, BytesN, Env, Error, Symbol, Val, + Vec, +}; + +/// Context of a single authorized call performed by an address. +/// +/// Custom account contracts that implement `__check_auth` special function +/// receive a list of `Context` values corresponding to all the calls that +/// need to be authorized. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub enum Context { + /// Contract invocation. + Contract(ContractContext), + /// Contract that has a constructor with no arguments is created. + CreateContractHostFn(CreateContractHostFnContext), + /// Contract that has a constructor with 1 or more arguments is created. + CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext), +} + +/// Authorization context of a single contract call. +/// +/// This struct corresponds to a `require_auth_for_args` call for an address +/// from `contract` function with `fn_name` name and `args` arguments. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub struct ContractContext { + pub contract: Address, + pub fn_name: Symbol, + pub args: Vec, +} + +/// Authorization context for `create_contract` host function that creates a +/// new contract on behalf of authorizer address. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub struct CreateContractHostFnContext { + pub executable: ContractExecutable, + pub salt: BytesN<32>, +} + +/// Authorization context for `create_contract` host function that creates a +/// new contract on behalf of authorizer address. +/// This is the same as `CreateContractHostFnContext`, but also has +/// contract constructor arguments. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub struct CreateContractWithConstructorHostFnContext { + pub executable: ContractExecutable, + pub salt: BytesN<32>, + pub constructor_args: Vec, +} + +/// Contract executable used for creating a new contract and used in +/// `CreateContractHostFnContext`. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub enum ContractExecutable { + Wasm(BytesN<32>), +} + +/// A node in the tree of authorizations performed on behalf of the current +/// contract as invoker of the contracts deeper in the call stack. +/// +/// This is used as an argument of `authorize_as_current_contract` host function. +/// +/// This tree corresponds `require_auth[_for_args]` calls on behalf of the +/// current contract. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub enum InvokerContractAuthEntry { + /// Invoke a contract. + Contract(SubContractInvocation), + /// Create a contract passing 0 arguments to constructor. + CreateContractHostFn(CreateContractHostFnContext), + /// Create a contract passing 0 or more arguments to constructor. + CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext), +} + +/// Value of contract node in InvokerContractAuthEntry tree. +#[derive(Clone)] +#[contracttype(crate_path = "crate", export = false)] +pub struct SubContractInvocation { + pub context: ContractContext, + pub sub_invocations: Vec, +} + +/// Custom account interface that a contract implements to support being used +/// as a custom account for auth. +/// +/// Once a contract implements the interface, call to [`Address::require_auth`] +/// for the contract's address will call its `__check_auth` implementation. +#[contractimpl_trait_macro(crate_path = "crate")] +pub trait CustomAccountInterface { + type Signature; + type Error: Into; + + /// Check that the signatures and auth contexts are valid. + fn __check_auth( + env: Env, + signature_payload: Hash<32>, + signatures: Self::Signature, + auth_contexts: Vec, + ) -> Result<(), Self::Error>; +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/bytes.rs b/temp_sdk/soroban-sdk-26.0.1/src/bytes.rs new file mode 100644 index 0000000..511d1b7 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/bytes.rs @@ -0,0 +1,1839 @@ +#[cfg(feature = "alloc")] +extern crate alloc; + +use core::{ + borrow::Borrow, + cmp::Ordering, + convert::Infallible, + fmt::Debug, + iter::FusedIterator, + ops::{Bound, RangeBounds}, +}; + +use super::{ + env::internal::{BytesObject, Env as _, EnvBase as _}, + env::IntoVal, + ConversionError, Env, String, TryFromVal, TryIntoVal, Val, +}; + +use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; +#[cfg(doc)] +use crate::{storage::Storage, Map, Vec}; + +#[cfg(not(target_family = "wasm"))] +use super::xdr::ScVal; + +/// Create a [Bytes] with an array, or an integer or hex literal. +/// +/// The first argument in the list must be a reference to an [Env]. +/// +/// The second argument can be an [u8] array, or an integer literal of unbounded +/// size in any form: base10, hex, etc. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{Env, bytes}; +/// +/// let env = Env::default(); +/// let bytes = bytes!(&env, 0xfded3f55dec47250a52a8c0bb7038e72fa6ffaae33562f77cd2b629ef7fd424d); +/// assert_eq!(bytes.len(), 32); +/// ``` +/// +/// ``` +/// use soroban_sdk::{Env, bytes}; +/// +/// let env = Env::default(); +/// let bytes = bytes!(&env, [2, 0]); +/// assert_eq!(bytes.len(), 2); +/// ``` +/// +/// ``` +/// use soroban_sdk::{Env, bytes}; +/// +/// let env = Env::default(); +/// let bytes = bytes!(&env); +/// assert_eq!(bytes.len(), 0); +/// ``` +#[macro_export] +macro_rules! bytes { + ($env:expr $(,)?) => { + $crate::Bytes::new($env) + }; + ($env:expr, [$($x:expr),+ $(,)?] $(,)?) => { + $crate::Bytes::from_array($env, &[$($x),+]) + }; + ($env:expr, $x:tt $(,)?) => { + $crate::Bytes::from_array($env, &$crate::reexports_for_macros::bytes_lit::bytes!($x)) + }; +} + +/// Create a [BytesN] with an array, or an integer or hex literal. +/// +/// The first argument in the list must be a reference to an [Env]. +/// +/// The second argument can be an [u8] array, or an integer literal of unbounded +/// size in any form: base10, hex, etc. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{Env, bytesn}; +/// +/// let env = Env::default(); +/// let bytes = bytesn!(&env, 0xfded3f55dec47250a52a8c0bb7038e72fa6ffaae33562f77cd2b629ef7fd424d); +/// assert_eq!(bytes.len(), 32); +/// ``` +/// +/// ``` +/// use soroban_sdk::{Env, bytesn}; +/// +/// let env = Env::default(); +/// let bytes = bytesn!(&env, [2, 0]); +/// assert_eq!(bytes.len(), 2); +/// ``` +#[macro_export] +macro_rules! bytesn { + ($env:expr, [$($x:expr),+ $(,)?] $(,)?) => { + $crate::BytesN::from_array($env, &[$($x),+]) + }; + ($env:expr, $x:tt $(,)?) => { + $crate::BytesN::from_array($env, &$crate::reexports_for_macros::bytes_lit::bytes!($x)) + }; +} + +/// Internal macro that generates all `BytesN` wrapper methods and trait impls +/// *except* `from_bytes`. Types using this macro must provide their own +/// `from_bytes(BytesN<$size>) -> Self` (e.g. to add validation). +#[doc(hidden)] +macro_rules! impl_bytesn_repr { + ($elem: ident, $size: expr) => { + impl $elem { + pub fn into_bytes(self) -> BytesN<$size> { + self.0 + } + + pub fn to_bytes(&self) -> BytesN<$size> { + self.0.clone() + } + + pub fn as_bytes(&self) -> &BytesN<$size> { + &self.0 + } + + pub fn to_array(&self) -> [u8; $size] { + self.0.to_array() + } + + pub fn from_array(env: &Env, array: &[u8; $size]) -> Self { + Self::from_bytes(BytesN::from_array(env, array)) + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn as_object(&self) -> &BytesObject { + self.0.as_object() + } + + pub fn to_object(&self) -> BytesObject { + self.0.to_object() + } + } + + impl TryFromVal for $elem { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + let bytes = BytesN::try_from_val(env, val)?; + Ok(Self::from_bytes(bytes)) + } + } + + impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, elt: &$elem) -> Result { + Ok(elt.to_val()) + } + } + + impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, elt: &&$elem) -> Result { + Ok(elt.to_val()) + } + } + + #[cfg(not(target_family = "wasm"))] + impl From<&$elem> for ScVal { + fn from(v: &$elem) -> Self { + Self::from(&v.0) + } + } + + #[cfg(not(target_family = "wasm"))] + impl From<$elem> for ScVal { + fn from(v: $elem) -> Self { + (&v).into() + } + } + + impl IntoVal> for $elem { + fn into_val(&self, _e: &Env) -> BytesN<$size> { + self.0.clone() + } + } + + impl From<$elem> for Bytes { + fn from(v: $elem) -> Self { + v.0.into() + } + } + + impl From<$elem> for BytesN<$size> { + fn from(v: $elem) -> Self { + v.0 + } + } + + impl Into<[u8; $size]> for $elem { + fn into(self) -> [u8; $size] { + self.0.into() + } + } + + impl Eq for $elem {} + + impl PartialEq for $elem { + fn eq(&self, other: &Self) -> bool { + self.0.partial_cmp(other.as_bytes()) == Some(Ordering::Equal) + } + } + + impl Debug for $elem { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}({:?})", stringify!($elem), self.to_array()) + } + } + }; +} + +/// Bytes is a contiguous growable array type containing `u8`s. +/// +/// The array is stored in the Host and available to the Guest through the +/// functions defined on Bytes. +/// +/// Bytes values can be stored as [Storage], or in other types like [Vec], +/// [Map], etc. +/// +/// ### Examples +/// +/// Bytes values can be created from slices: +/// ``` +/// use soroban_sdk::{Bytes, Env}; +/// +/// let env = Env::default(); +/// let bytes = Bytes::from_slice(&env, &[1; 32]); +/// assert_eq!(bytes.len(), 32); +/// let mut slice = [0u8; 32]; +/// bytes.copy_into_slice(&mut slice); +/// assert_eq!(slice, [1u8; 32]); +/// ``` +#[derive(Clone)] +pub struct Bytes { + env: Env, + obj: BytesObject, +} + +impl Debug for Bytes { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Bytes(")?; + let mut iter = self.iter(); + if let Some(x) = iter.next() { + write!(f, "{:?}", x)?; + } + for x in iter { + write!(f, ", {:?}", x)?; + } + write!(f, ")")?; + Ok(()) + } +} + +impl Eq for Bytes {} + +impl PartialEq for Bytes { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Bytes { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + #[cfg(not(target_family = "wasm"))] + if !self.env.is_same_env(&other.env) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = self + .env + .obj_cmp(self.obj.to_val(), other.obj.to_val()) + .unwrap_infallible(); + v.cmp(&0) + } +} + +impl TryFromVal for Bytes { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &Bytes) -> Result { + Ok(v.clone()) + } +} + +impl TryFromVal for Bytes { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &BytesObject) -> Result { + Ok(unsafe { Bytes::unchecked_new(env.clone(), *val) }) + } +} + +impl TryFromVal for Bytes { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(BytesObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &Bytes) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&Bytes) -> Result { + Ok(v.to_val()) + } +} + +impl From for Val { + #[inline(always)] + fn from(v: Bytes) -> Self { + v.obj.into() + } +} + +impl From for BytesObject { + #[inline(always)] + fn from(v: Bytes) -> Self { + v.obj + } +} + +impl From<&Bytes> for BytesObject { + #[inline(always)] + fn from(v: &Bytes) -> Self { + v.obj + } +} + +impl From<&Bytes> for Bytes { + #[inline(always)] + fn from(v: &Bytes) -> Self { + v.clone() + } +} + +impl From<&Bytes> for String { + fn from(v: &Bytes) -> Self { + Env::bytes_to_string(&v.env, v.obj.clone()) + .unwrap_infallible() + .into_val(&v.env) + } +} + +impl From for String { + fn from(v: Bytes) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Bytes> for ScVal { + fn from(v: &Bytes) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for ScVal { + fn from(v: Bytes) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Bytes { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok( + BytesObject::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible(), + ) + } +} + +impl TryFromVal for Bytes { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &&str) -> Result { + Ok(Bytes::from_slice(env, v.as_bytes())) + } +} + +impl TryFromVal for Bytes { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &&[u8]) -> Result { + Ok(Bytes::from_slice(env, v)) + } +} + +impl TryFromVal for Bytes { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &[u8; N]) -> Result { + Ok(Bytes::from_array(env, v)) + } +} + +impl Bytes { + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: BytesObject) -> Self { + Self { env, obj } + } + + #[inline(always)] + pub fn env(&self) -> &Env { + &self.env + } + + pub fn as_val(&self) -> &Val { + self.obj.as_val() + } + + pub fn to_val(&self) -> Val { + self.obj.to_val() + } + + pub fn as_object(&self) -> &BytesObject { + &self.obj + } + + pub fn to_object(&self) -> BytesObject { + self.obj + } +} + +impl Bytes { + /// Create an empty Bytes. + #[inline(always)] + pub fn new(env: &Env) -> Bytes { + let obj = env.bytes_new().unwrap_infallible(); + unsafe { Self::unchecked_new(env.clone(), obj) } + } + + /// Create a Bytes from the array. + #[inline(always)] + pub fn from_array(env: &Env, items: &[u8; N]) -> Bytes { + Self::from_slice(env, items) + } + + /// Create a Bytes from the slice. + #[inline(always)] + pub fn from_slice(env: &Env, items: &[u8]) -> Bytes { + Bytes { + env: env.clone(), + obj: env.bytes_new_from_slice(items).unwrap_optimized(), + } + } + + /// Sets the byte at the position with new value. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn set(&mut self, i: u32, v: u8) { + let v32: u32 = v.into(); + self.obj = self + .env() + .bytes_put(self.obj, i.into(), v32.into()) + .unwrap_infallible() + } + + /// Returns the byte at the position or None if out-of-bounds. + #[inline(always)] + pub fn get(&self, i: u32) -> Option { + if i < self.len() { + Some(self.get_unchecked(i)) + } else { + None + } + } + + /// Returns the byte at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn get_unchecked(&self, i: u32) -> u8 { + let res32_val = self.env().bytes_get(self.obj, i.into()).unwrap_infallible(); + let res32: u32 = res32_val.into(); + res32 as u8 + } + + /// Returns true if the Bytes is empty and has a length of zero. + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of bytes are in the Bytes. + #[inline(always)] + pub fn len(&self) -> u32 { + self.env().bytes_len(self.obj).unwrap_infallible().into() + } + + /// Returns the first byte or None if empty. + #[inline(always)] + pub fn first(&self) -> Option { + if !self.is_empty() { + Some(self.first_unchecked()) + } else { + None + } + } + + /// Returns the first byte. + /// + /// ### Panics + /// + /// If the Bytes is empty. + #[inline(always)] + pub fn first_unchecked(&self) -> u8 { + let res: u32 = self.env().bytes_front(self.obj).unwrap_infallible().into(); + res as u8 + } + + /// Returns the last byte or None if empty. + #[inline(always)] + pub fn last(&self) -> Option { + if !self.is_empty() { + Some(self.last_unchecked()) + } else { + None + } + } + + /// Returns the last byte. + /// + /// ### Panics + /// + /// If the Bytes is empty. + #[inline(always)] + pub fn last_unchecked(&self) -> u8 { + let res: u32 = self.env().bytes_back(self.obj).unwrap_infallible().into(); + res as u8 + } + + /// Removes the byte at the position. + /// + /// Returns `None` if out-of-bounds. + #[inline(always)] + pub fn remove(&mut self, i: u32) -> Option<()> { + if i < self.len() { + self.remove_unchecked(i); + Some(()) + } else { + None + } + } + + /// Removes the byte at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn remove_unchecked(&mut self, i: u32) { + self.obj = self.env().bytes_del(self.obj, i.into()).unwrap_infallible() + } + + /// Adds the byte to the back. + /// + /// Increases the length by one and puts the byte in the last position. + #[inline(always)] + pub fn push_back(&mut self, x: u8) { + let x32: u32 = x.into(); + self.obj = self + .env() + .bytes_push(self.obj, x32.into()) + .unwrap_infallible() + } + + /// Removes and returns the last byte or None if empty. + #[inline(always)] + pub fn pop_back(&mut self) -> Option { + let last = self.last()?; + self.obj = self.env().bytes_pop(self.obj).unwrap_infallible(); + Some(last) + } + + /// Removes and returns the last byte or None if empty. + /// + /// ### Panics + /// + /// If the Bytes is empty. + #[inline(always)] + pub fn pop_back_unchecked(&mut self) -> u8 { + let last = self.last_unchecked(); + self.obj = self.env().bytes_pop(self.obj).unwrap_infallible(); + last + } + + /// Insert the byte at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn insert(&mut self, i: u32, b: u8) { + let b32: u32 = b.into(); + self.obj = self + .env() + .bytes_insert(self.obj, i.into(), b32.into()) + .unwrap_infallible() + } + + /// Insert the bytes at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn insert_from_bytes(&mut self, i: u32, bytes: Bytes) { + let mut result = self.slice(..i); + result.append(&bytes); + result.append(&self.slice(i..)); + *self = result + } + + /// Insert the bytes at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn insert_from_array(&mut self, i: u32, array: &[u8; N]) { + self.insert_from_slice(i, array) + } + + /// Insert the bytes at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn insert_from_slice(&mut self, i: u32, slice: &[u8]) { + self.insert_from_bytes(i, Bytes::from_slice(self.env(), slice)) + } + + /// Append the bytes. + #[inline(always)] + pub fn append(&mut self, other: &Bytes) { + self.obj = self + .env() + .bytes_append(self.obj, other.obj) + .unwrap_infallible() + } + + /// Extend with the bytes in the array. + #[inline(always)] + pub fn extend_from_array(&mut self, array: &[u8; N]) { + self.extend_from_slice(array) + } + + /// Extend with the bytes in the slice. + #[inline(always)] + pub fn extend_from_slice(&mut self, slice: &[u8]) { + self.obj = self + .env() + .bytes_copy_from_slice(self.to_object(), self.len().into(), slice) + .unwrap_optimized() + } + + /// Copy the bytes from slice. + /// + /// The full number of bytes in slice are always copied and [Bytes] is grown + /// if necessary. + #[inline(always)] + pub fn copy_from_slice(&mut self, i: u32, slice: &[u8]) { + self.obj = self + .env() + .bytes_copy_from_slice(self.to_object(), i.into(), slice) + .unwrap_optimized() + } + + /// Copy the bytes into the given slice. + /// + /// ### Panics + /// + /// If the output slice and bytes are of different lengths. + #[inline(always)] + pub fn copy_into_slice(&self, slice: &mut [u8]) { + let env = self.env(); + if self.len() as usize != slice.len() { + sdk_panic!("Bytes::copy_into_slice with mismatched slice length") + } + env.bytes_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) + .unwrap_optimized(); + } + + /// Returns a subset of the bytes as defined by the start and end bounds of + /// the range. + /// + /// ### Panics + /// + /// If the range is out-of-bounds. + #[must_use] + pub fn slice(&self, r: impl RangeBounds) -> Self { + let start_bound = match r.start_bound() { + Bound::Included(s) => *s, + Bound::Excluded(s) => s + .checked_add(1) + .expect_optimized("attempt to add with overflow"), + Bound::Unbounded => 0, + }; + let end_bound = match r.end_bound() { + Bound::Included(s) => s + .checked_add(1) + .expect_optimized("attempt to add with overflow"), + Bound::Excluded(s) => *s, + Bound::Unbounded => self.len(), + }; + let env = self.env(); + let bin = env + .bytes_slice(self.obj, start_bound.into(), end_bound.into()) + .unwrap_infallible(); + unsafe { Self::unchecked_new(env.clone(), bin) } + } + + pub fn iter(&self) -> BytesIter { + self.clone().into_iter() + } + + /// Copy the bytes into a buffer of given size. + /// + /// Returns the buffer and a range of where the bytes live in the given + /// buffer. + /// + /// Suitable when the size of the bytes isn't a fixed size but it is known + /// to be under a certain size, or failure due to overflow is acceptable. + /// + /// ### Panics + /// + /// If the size of the bytes is larger than the size of the buffer. To avoid + /// this, first slice the bytes into a smaller size then convert to a + /// buffer. + #[must_use] + pub fn to_buffer(&self) -> BytesBuffer { + let mut buffer = [0u8; B]; + let len = self.len() as usize; + { + let slice = &mut buffer[0..len]; + self.copy_into_slice(slice); + } + BytesBuffer { buffer, len } + } + + /// Copy the bytes into a Rust alloc Vec of size matching the bytes. + /// + /// Returns the Vec. Allocates using the built-in allocator. + /// + /// Suitable when the size of the bytes isn't a fixed size and the allocator + /// functionality of the sdk is enabled. + #[cfg(feature = "alloc")] + #[must_use] + pub fn to_alloc_vec(&self) -> alloc::vec::Vec { + let len = self.len() as usize; + let mut vec = alloc::vec::from_elem(0u8, len); + self.copy_into_slice(&mut vec); + vec + } + + /// Converts the contents of the Bytes into a respective String object. + /// + /// The conversion doesn't try to interpret the bytes as any particular + /// encoding, as the SDK `String` type doesn't assume any encoding either. + pub fn to_string(&self) -> String { + self.into() + } +} + +/// A `BytesBuffer` stores a variable number of bytes, up to a fixed limit `B`. +/// +/// The bytes are stored in a fixed-size non-heap-allocated structure. It is a +/// minimal wrapper around a fixed-size `[u8;B]` byte array and a length field +/// indicating the amount of the byte array containing meaningful data. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BytesBuffer { + buffer: [u8; B], + len: usize, +} + +impl Borrow<[u8]> for BytesBuffer { + /// Returns a borrow slice of the bytes stored in the BytesBuffer. + fn borrow(&self) -> &[u8] { + self.as_slice() + } +} + +impl BytesBuffer { + /// Returns a borrow slice of the bytes stored in the BytesBuffer. + pub fn as_slice(&self) -> &[u8] { + &self.buffer[..self.len] + } +} + +impl IntoIterator for Bytes { + type Item = u8; + type IntoIter = BytesIter; + + fn into_iter(self) -> Self::IntoIter { + BytesIter(self) + } +} + +#[derive(Clone)] +pub struct BytesIter(Bytes); + +impl BytesIter { + fn into_bin(self) -> Bytes { + self.0 + } +} + +impl Iterator for BytesIter { + type Item = u8; + + fn next(&mut self) -> Option { + if self.0.is_empty() { + None + } else { + let val: u32 = self + .0 + .env() + .bytes_front(self.0.obj) + .unwrap_infallible() + .into(); + self.0 = self.0.slice(1..); + Some(val as u8) + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.0.len() as usize; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for BytesIter { + fn next_back(&mut self) -> Option { + let len = self.0.len(); + if len == 0 { + None + } else { + let val: u32 = self + .0 + .env() + .bytes_back(self.0.obj) + .unwrap_infallible() + .into(); + self.0 = self.0.slice(..len - 1); + Some(val as u8) + } + } +} + +impl FusedIterator for BytesIter {} + +impl ExactSizeIterator for BytesIter { + fn len(&self) -> usize { + self.0.len() as usize + } +} + +/// BytesN is a contiguous fixed-size array type containing `u8`s. +/// +/// The array is stored in the Host and available to the Guest through the +/// functions defined on Bytes. +/// +/// Bytes values can be stored as [Storage], or in other types like [Vec], [Map], +/// etc. +/// +/// ### Examples +/// +/// BytesN values can be created from arrays: +/// ``` +/// use soroban_sdk::{Bytes, BytesN, Env}; +/// +/// let env = Env::default(); +/// let bytes = BytesN::from_array(&env, &[0; 32]); +/// assert_eq!(bytes.len(), 32); +/// ``` +/// +/// BytesN and Bytes values are convertible: +/// ``` +/// use soroban_sdk::{Bytes, BytesN, Env}; +/// +/// let env = Env::default(); +/// let bytes = Bytes::from_slice(&env, &[0; 32]); +/// let bytes: BytesN<32> = bytes.try_into().expect("bytes to have length 32"); +/// assert_eq!(bytes.len(), 32); +/// ``` +#[derive(Clone)] +#[repr(transparent)] +pub struct BytesN(Bytes); + +impl Debug for BytesN { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "BytesN<{}>(", N)?; + let mut iter = self.iter(); + if let Some(x) = iter.next() { + write!(f, "{:?}", x)?; + } + for x in iter { + write!(f, ", {:?}", x)?; + } + write!(f, ")")?; + Ok(()) + } +} + +impl Eq for BytesN {} + +impl PartialEq for BytesN { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialEq<[u8; N]> for BytesN { + fn eq(&self, other: &[u8; N]) -> bool { + let other: BytesN = other.into_val(self.env()); + self.eq(&other) + } +} + +impl PartialEq> for [u8; N] { + fn eq(&self, other: &BytesN) -> bool { + let self_: BytesN = self.into_val(other.env()); + self_.eq(other) + } +} + +impl PartialOrd for BytesN { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl PartialOrd<[u8; N]> for BytesN { + fn partial_cmp(&self, other: &[u8; N]) -> Option { + let other: BytesN = other.into_val(self.env()); + self.partial_cmp(&other) + } +} + +impl PartialOrd> for [u8; N] { + fn partial_cmp(&self, other: &BytesN) -> Option { + let self_: BytesN = self.into_val(other.env()); + self_.partial_cmp(other) + } +} + +impl Ord for BytesN { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl Borrow for BytesN { + fn borrow(&self) -> &Bytes { + &self.0 + } +} + +impl Borrow for &BytesN { + fn borrow(&self) -> &Bytes { + &self.0 + } +} + +impl Borrow for &mut BytesN { + fn borrow(&self) -> &Bytes { + &self.0 + } +} + +impl AsRef for BytesN { + fn as_ref(&self) -> &Bytes { + &self.0 + } +} + +impl TryFromVal> for BytesN { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &BytesN) -> Result { + Ok(v.clone()) + } +} + +impl TryFromVal> for Bytes { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &BytesN) -> Result { + Ok(v.0.clone()) + } +} + +impl TryFromVal for BytesN { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &[u8; N]) -> Result { + Ok(BytesN::from_array(env, v)) + } +} + +impl TryFromVal> for [u8; N] { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &BytesN) -> Result { + Ok(v.to_array()) + } +} + +impl TryFromVal for BytesN { + type Error = ConversionError; + + fn try_from_val(env: &Env, obj: &BytesObject) -> Result { + Bytes::try_from_val(env, obj).unwrap_infallible().try_into() + } +} + +impl TryFromVal for BytesN { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Bytes::try_from_val(env, val)?.try_into() + } +} + +impl TryFromVal> for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &BytesN) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal> for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&BytesN) -> Result { + Ok(v.to_val()) + } +} + +impl TryFrom for BytesN { + type Error = ConversionError; + + #[inline(always)] + fn try_from(bin: Bytes) -> Result { + if bin.len() == { N as u32 } { + Ok(Self(bin)) + } else { + Err(ConversionError {}) + } + } +} + +impl TryFrom<&Bytes> for BytesN { + type Error = ConversionError; + + #[inline(always)] + fn try_from(bin: &Bytes) -> Result { + bin.clone().try_into() + } +} + +impl From> for Val { + #[inline(always)] + fn from(v: BytesN) -> Self { + v.0.into() + } +} + +impl From> for Bytes { + #[inline(always)] + fn from(v: BytesN) -> Self { + v.into_bytes() + } +} + +impl From<&BytesN> for Bytes { + #[inline(always)] + fn from(v: &BytesN) -> Self { + v.to_bytes() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&BytesN> for ScVal { + fn from(v: &BytesN) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.0.env, &v.0.obj.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From> for ScVal { + fn from(v: BytesN) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for BytesN { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Bytes::try_from_val(env, val)?.try_into() + } +} + +impl BytesN { + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: BytesObject) -> Self { + Self(Bytes::unchecked_new(env, obj)) + } + + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn as_bytes(&self) -> &Bytes { + &self.0 + } + + pub fn into_bytes(self) -> Bytes { + self.0 + } + + pub fn to_bytes(&self) -> Bytes { + self.0.clone() + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn as_object(&self) -> &BytesObject { + self.0.as_object() + } + + pub fn to_object(&self) -> BytesObject { + self.0.to_object() + } + + /// Create a BytesN from the slice. + #[inline(always)] + pub fn from_array(env: &Env, items: &[u8; N]) -> BytesN { + BytesN(Bytes::from_slice(env, items)) + } + + /// Sets the byte at the position with new value. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn set(&mut self, i: u32, v: u8) { + self.0.set(i, v); + } + + /// Returns the byte at the position or None if out-of-bounds. + #[inline(always)] + pub fn get(&self, i: u32) -> Option { + self.0.get(i) + } + + /// Returns the byte at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn get_unchecked(&self, i: u32) -> u8 { + self.0.get_unchecked(i) + } + + /// Returns true if the Bytes is empty and has a length of zero. + #[inline(always)] + pub fn is_empty(&self) -> bool { + N == 0 + } + + /// Returns the number of bytes are in the Bytes. + #[inline(always)] + pub fn len(&self) -> u32 { + N as u32 + } + + /// Returns the first byte or None if empty. + #[inline(always)] + pub fn first(&self) -> Option { + self.0.first() + } + + /// Returns the first byte. + /// + /// ### Panics + /// + /// If the Bytes is empty. + #[inline(always)] + pub fn first_unchecked(&self) -> u8 { + self.0.first_unchecked() + } + + /// Returns the last byte or None if empty. + #[inline(always)] + pub fn last(&self) -> Option { + self.0.last() + } + + /// Returns the last byte. + /// + /// ### Panics + /// + /// If the Bytes is empty. + #[inline(always)] + pub fn last_unchecked(&self) -> u8 { + self.0.last_unchecked() + } + + /// Copy the bytes into the given slice. + #[inline(always)] + pub fn copy_into_slice(&self, slice: &mut [u8; N]) { + let env = self.env(); + env.bytes_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) + .unwrap_optimized(); + } + + /// Copy the bytes in [BytesN] into an array. + #[inline(always)] + pub fn to_array(&self) -> [u8; N] { + let mut array = [0u8; N]; + self.copy_into_slice(&mut array); + array + } + + pub fn iter(&self) -> BytesIter { + self.clone().into_iter() + } +} + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl crate::testutils::BytesN for BytesN { + fn random(env: &Env) -> BytesN { + BytesN::from_array(env, &crate::testutils::random()) + } +} + +impl IntoIterator for BytesN { + type Item = u8; + + type IntoIter = BytesIter; + + fn into_iter(self) -> Self::IntoIter { + BytesIter(self.0) + } +} + +impl TryFrom for [u8; N] { + type Error = ConversionError; + + fn try_from(bin: Bytes) -> Result { + let fixed: BytesN = bin.try_into()?; + Ok(fixed.into()) + } +} + +impl TryFrom<&Bytes> for [u8; N] { + type Error = ConversionError; + + fn try_from(bin: &Bytes) -> Result { + let fixed: BytesN = bin.try_into()?; + Ok(fixed.into()) + } +} + +impl From> for [u8; N] { + fn from(bin: BytesN) -> Self { + let mut res = [0u8; N]; + for (i, b) in bin.into_iter().enumerate() { + res[i] = b; + } + res + } +} + +impl From<&BytesN> for [u8; N] { + fn from(bin: &BytesN) -> Self { + let mut res = [0u8; N]; + for (i, b) in bin.iter().enumerate() { + res[i] = b; + } + res + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn bytes_from_and_to_slices() { + let env = Env::default(); + + let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); + let mut out = [0u8; 4]; + b.copy_into_slice(&mut out); + assert_eq!([1, 2, 3, 4], out); + + let mut b = Bytes::from_slice(&env, &[1, 2, 3, 4]); + b.extend_from_slice(&[5, 6, 7, 8]); + b.insert_from_slice(1, &[9, 10]); + b.insert_from_bytes(4, Bytes::from_slice(&env, &[0, 0])); + let mut out = [0u8; 12]; + b.copy_into_slice(&mut out); + assert_eq!([1, 9, 10, 2, 0, 0, 3, 4, 5, 6, 7, 8], out); + b.copy_from_slice(3, &[7, 6, 5]); + b.copy_into_slice(&mut out); + assert_eq!([1, 9, 10, 7, 6, 5, 3, 4, 5, 6, 7, 8], out); + } + + #[test] + fn bytesn_from_and_to_slices() { + let env = Env::default(); + + let b = BytesN::from_array(&env, &[1, 2, 3, 4]); + let mut out = [0u8; 4]; + b.copy_into_slice(&mut out); + assert_eq!([1, 2, 3, 4], out); + } + + #[test] + #[should_panic] + fn bytes_to_short_slice() { + let env = Env::default(); + let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); + let mut out = [0u8; 3]; + b.copy_into_slice(&mut out); + } + + #[test] + #[should_panic] + fn bytes_to_long_slice() { + let env = Env::default(); + let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); + let mut out = [0u8; 5]; + b.copy_into_slice(&mut out); + } + + #[test] + fn macro_bytes() { + let env = Env::default(); + assert_eq!(bytes!(&env), Bytes::new(&env)); + assert_eq!(bytes!(&env, 1), { + let mut b = Bytes::new(&env); + b.push_back(1); + b + }); + assert_eq!(bytes!(&env, 1,), { + let mut b = Bytes::new(&env); + b.push_back(1); + b + }); + assert_eq!(bytes!(&env, [3, 2, 1,]), { + let mut b = Bytes::new(&env); + b.push_back(3); + b.push_back(2); + b.push_back(1); + b + }); + } + + #[test] + fn macro_bytes_hex() { + let env = Env::default(); + assert_eq!(bytes!(&env), Bytes::new(&env)); + assert_eq!(bytes!(&env, 1), { + let mut b = Bytes::new(&env); + b.push_back(1); + b + }); + assert_eq!(bytes!(&env, 1,), { + let mut b = Bytes::new(&env); + b.push_back(1); + b + }); + assert_eq!(bytes!(&env, 0x30201), { + let mut b = Bytes::new(&env); + b.push_back(3); + b.push_back(2); + b.push_back(1); + b + }); + assert_eq!(bytes!(&env, 0x0000030201), { + Bytes::from_array(&env, &[0, 0, 3, 2, 1]) + }); + } + + #[test] + fn macro_bytesn() { + let env = Env::default(); + assert_eq!(bytesn!(&env, 1), { BytesN::from_array(&env, &[1]) }); + assert_eq!(bytesn!(&env, 1,), { BytesN::from_array(&env, &[1]) }); + assert_eq!(bytesn!(&env, [3, 2, 1,]), { + BytesN::from_array(&env, &[3, 2, 1]) + }); + } + + #[test] + fn macro_bytesn_hex() { + let env = Env::default(); + assert_eq!(bytesn!(&env, 0x030201), { + BytesN::from_array(&env, &[3, 2, 1]) + }); + assert_eq!(bytesn!(&env, 0x0000030201), { + BytesN::from_array(&env, &[0, 0, 3, 2, 1]) + }); + } + + #[test] + fn test_bin() { + let env = Env::default(); + + let mut bin = Bytes::new(&env); + assert_eq!(bin.len(), 0); + bin.push_back(10); + assert_eq!(bin.len(), 1); + bin.push_back(20); + assert_eq!(bin.len(), 2); + bin.push_back(30); + assert_eq!(bin.len(), 3); + println!("{:?}", bin); + + let bin_ref = &bin; + assert_eq!(bin_ref.len(), 3); + + let mut bin_copy = bin.clone(); + assert!(bin == bin_copy); + assert_eq!(bin_copy.len(), 3); + bin_copy.push_back(40); + assert_eq!(bin_copy.len(), 4); + assert!(bin != bin_copy); + + assert_eq!(bin.len(), 3); + assert_eq!(bin_ref.len(), 3); + + bin_copy.pop_back(); + assert!(bin == bin_copy); + + let bad_fixed: Result, ConversionError> = bin.try_into(); + assert!(bad_fixed.is_err()); + let fixed: BytesN<3> = bin_copy.try_into().unwrap(); + println!("{:?}", fixed); + } + + #[test] + fn test_bin_iter() { + let env = Env::default(); + let mut bin = Bytes::new(&env); + bin.push_back(10); + bin.push_back(20); + bin.push_back(30); + let mut iter = bin.iter(); + assert_eq!(iter.next(), Some(10)); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.next(), Some(30)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + let mut iter = bin.iter(); + assert_eq!(iter.next(), Some(10)); + assert_eq!(iter.next_back(), Some(30)); + assert_eq!(iter.next_back(), Some(20)); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + + let fixed: BytesN<3> = bin.try_into().unwrap(); + let mut iter = fixed.iter(); + assert_eq!(iter.next(), Some(10)); + assert_eq!(iter.next(), Some(20)); + assert_eq!(iter.next(), Some(30)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + let mut iter = fixed.iter(); + assert_eq!(iter.next(), Some(10)); + assert_eq!(iter.next_back(), Some(30)); + assert_eq!(iter.next_back(), Some(20)); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + } + + #[test] + fn test_array_binary_borrow() { + fn get_len(b: impl Borrow) -> u32 { + let b: &Bytes = b.borrow(); + b.len() + } + + let env = Env::default(); + let mut bin = Bytes::new(&env); + bin.push_back(10); + bin.push_back(20); + bin.push_back(30); + assert_eq!(bin.len(), 3); + + let arr_bin: BytesN<3> = bin.clone().try_into().unwrap(); + assert_eq!(arr_bin.len(), 3); + + assert_eq!(get_len(&bin), 3); + assert_eq!(get_len(bin), 3); + assert_eq!(get_len(&arr_bin), 3); + assert_eq!(get_len(arr_bin), 3); + } + + #[test] + fn bytesn_debug() { + let env = Env::default(); + let mut bin = Bytes::new(&env); + bin.push_back(10); + bin.push_back(20); + bin.push_back(30); + let arr_bin: BytesN<3> = bin.clone().try_into().unwrap(); + assert_eq!(format!("{:?}", arr_bin), "BytesN<3>(10, 20, 30)"); + } + + #[test] + fn test_is_empty() { + let env = Env::default(); + let mut bin = Bytes::new(&env); + assert_eq!(bin.is_empty(), true); + bin.push_back(10); + assert_eq!(bin.is_empty(), false); + } + + #[test] + fn test_first() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + + assert_eq!(bin.first(), Some(1)); + bin.remove(0); + assert_eq!(bin.first(), Some(2)); + + // first on empty bytes + let bin = bytes![&env]; + assert_eq!(bin.first(), None); + } + + #[test] + fn test_first_unchecked() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + + assert_eq!(bin.first_unchecked(), 1); + bin.remove(0); + assert_eq!(bin.first_unchecked(), 2); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_first_unchecked_panics() { + let env = Env::default(); + let bin = bytes![&env]; + bin.first_unchecked(); + } + + #[test] + fn test_last() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + + assert_eq!(bin.last(), Some(4)); + bin.remove(3); + assert_eq!(bin.last(), Some(3)); + + // last on empty bytes + let bin = bytes![&env]; + assert_eq!(bin.last(), None); + } + + #[test] + fn test_last_unchecked() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + + assert_eq!(bin.last_unchecked(), 4); + bin.remove(3); + assert_eq!(bin.last_unchecked(), 3); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_last_unchecked_panics() { + let env = Env::default(); + let bin = bytes![&env]; + bin.last_unchecked(); + } + + #[test] + fn test_get() { + let env = Env::default(); + let bin = bytes![&env, [0, 1, 5, 2, 8]]; + + assert_eq!(bin.get(0), Some(0)); + assert_eq!(bin.get(1), Some(1)); + assert_eq!(bin.get(2), Some(5)); + assert_eq!(bin.get(3), Some(2)); + assert_eq!(bin.get(4), Some(8)); + + assert_eq!(bin.get(bin.len()), None); + assert_eq!(bin.get(bin.len() + 1), None); + assert_eq!(bin.get(u32::MAX), None); + + // tests on an empty vec + let bin = bytes![&env]; + assert_eq!(bin.get(0), None); + assert_eq!(bin.get(bin.len()), None); + assert_eq!(bin.get(bin.len() + 1), None); + assert_eq!(bin.get(u32::MAX), None); + } + + #[test] + fn test_get_unchecked() { + let env = Env::default(); + let bin = bytes![&env, [0, 1, 5, 2, 8]]; + + assert_eq!(bin.get_unchecked(0), 0); + assert_eq!(bin.get_unchecked(1), 1); + assert_eq!(bin.get_unchecked(2), 5); + assert_eq!(bin.get_unchecked(3), 2); + assert_eq!(bin.get_unchecked(4), 8); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_get_unchecked_panics() { + let env = Env::default(); + let bin = bytes![&env]; + bin.get_unchecked(0); + } + + #[test] + fn test_remove() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + + assert_eq!(bin.remove(2), Some(())); + assert_eq!(bin, bytes![&env, [1, 2, 4]]); + assert_eq!(bin.len(), 3); + + // out of bound removes + assert_eq!(bin.remove(bin.len()), None); + assert_eq!(bin.remove(bin.len() + 1), None); + assert_eq!(bin.remove(u32::MAX), None); + + // remove rest of items + assert_eq!(bin.remove(0), Some(())); + assert_eq!(bin.remove(0), Some(())); + assert_eq!(bin.remove(0), Some(())); + assert_eq!(bin, bytes![&env]); + assert_eq!(bin.len(), 0); + + // try remove from empty bytes + let mut bin = bytes![&env]; + assert_eq!(bin.remove(0), None); + assert_eq!(bin.remove(bin.len()), None); + assert_eq!(bin.remove(bin.len() + 1), None); + assert_eq!(bin.remove(u32::MAX), None); + } + + #[test] + fn test_remove_unchecked() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + + bin.remove_unchecked(2); + assert_eq!(bin, bytes![&env, [1, 2, 4]]); + assert_eq!(bin.len(), 3); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_remove_unchecked_panics() { + let env = Env::default(); + let mut bin = bytes![&env, [1, 2, 3, 4]]; + bin.remove_unchecked(bin.len()); + } + + #[test] + fn test_pop() { + let env = Env::default(); + let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; + + assert_eq!(bin.pop_back(), Some(4)); + assert_eq!(bin.pop_back(), Some(3)); + assert_eq!(bin.len(), 3); + assert_eq!(bin, bytes![&env, [0, 1, 2]]); + + // pop on empty bytes + let mut bin = bytes![&env]; + assert_eq!(bin.pop_back(), None); + } + + #[test] + fn test_pop_unchecked() { + let env = Env::default(); + let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; + + assert_eq!(bin.pop_back_unchecked(), 4); + assert_eq!(bin.pop_back_unchecked(), 3); + assert_eq!(bin.len(), 3); + assert_eq!(bin, bytes![&env, [0, 1, 2]]); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_pop_unchecked_panics() { + let env = Env::default(); + let mut bin = bytes![&env]; + bin.pop_back_unchecked(); + } + + #[test] + fn test_insert() { + let env = Env::default(); + let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; + + bin.insert(3, 42); + assert_eq!(bin, bytes![&env, [0, 1, 2, 42, 3, 4]]); + + // insert at start + bin.insert(0, 43); + assert_eq!(bin, bytes![&env, [43, 0, 1, 2, 42, 3, 4]]); + + // insert at end + bin.insert(bin.len(), 44); + assert_eq!(bin, bytes![&env, [43, 0, 1, 2, 42, 3, 4, 44]]); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_insert_panic() { + let env = Env::default(); + let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; + bin.insert(80, 44); + } + + #[test] + fn test_slice() { + let env = Env::default(); + let bin = bytes![&env, [0, 1, 2, 3, 4]]; + + let bin2 = bin.slice(2..); + assert_eq!(bin2, bytes![&env, [2, 3, 4]]); + + let bin3 = bin.slice(3..3); + assert_eq!(bin3, bytes![&env]); + + let bin4 = bin.slice(0..3); + assert_eq!(bin4, bytes![&env, [0, 1, 2]]); + + let bin4 = bin.slice(3..5); + assert_eq!(bin4, bytes![&env, [3, 4]]); + + assert_eq!(bin, bytes![&env, [0, 1, 2, 3, 4]]); // makes sure original bytes is unchanged + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_slice_panic() { + let env = Env::default(); + let bin = bytes![&env, [0, 1, 2, 3, 4]]; + let _ = bin.slice(..=bin.len()); + } + + #[test] + fn test_bytes_to_string() { + let env = Env::default(); + let b: Bytes = bytes![&env, [0, 1, 2, 3, 4]]; + let s: String = b.clone().into(); + assert_eq!(s.len(), 5); + let mut slice = [0u8; 5]; + s.copy_into_slice(&mut slice); + assert_eq!(slice, [0, 1, 2, 3, 4]); + let s2 = b.to_string(); + assert_eq!(s, s2); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs b/temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs new file mode 100644 index 0000000..e493594 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs @@ -0,0 +1,32 @@ +use crate::{Env, IntoVal, Val, Vec}; + +pub trait ConstructorArgs: IntoVal> {} + +impl ConstructorArgs for Vec {} + +macro_rules! impl_constructor_args_for_tuple { + ( $($typ:ident $idx:tt)* ) => { + impl<$($typ),*> ConstructorArgs for ($($typ,)*) + where + $($typ: IntoVal),* + { + } + }; +} + +// 0 topics +impl ConstructorArgs for () {} +// 1-13 topics +impl_constructor_args_for_tuple! { T0 0 } +impl_constructor_args_for_tuple! { T0 0 T1 1 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 } +impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 } diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto.rs new file mode 100644 index 0000000..daec7d5 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/crypto.rs @@ -0,0 +1,396 @@ +//! Crypto contains functions for cryptographic functions. + +use crate::{ + env::internal::{self, BytesObject}, + unwrap::UnwrapInfallible, + Bytes, BytesN, ConversionError, Env, IntoVal, Symbol, TryFromVal, TryIntoVal, Val, Vec, U256, +}; + +pub mod bls12_381; +pub mod bn254; +pub(crate) mod utils; +/// Deprecated alias for `bn254::Bn254Fr`. +/// Use `bn254::Bn254Fr` directly instead. +#[deprecated(note = "use `bn254::Bn254Fr` instead")] +pub use bn254::Bn254Fr as BnScalar; + +/// A `BytesN` intended to contain the output of a cryptographic hash +/// function. +/// +/// When a `Hash` is returned by [`sha256`][Crypto::sha256] or +/// [`keccak256`][Crypto::keccak256], the SDK guarantees that the bytes came +/// from the corresponding secure cryptographic hash function. The host also +/// provides this guarantee for the first parameter of +/// [`CustomAccountInterface::__check_auth`][crate::auth::CustomAccountInterface::__check_auth]. +/// +/// `Hash` is represented at contract boundaries as `BytesN`, so accepting +/// it as a general contract entrypoint argument does not prove that the caller +/// supplied bytes were produced by a secure cryptographic hash function. Use +/// `BytesN` for externally supplied digests. +/// +/// **__Note:_** A Hash should not be used with storage, since no guarantee can +/// be made about the Bytes stored as to whether they were in fact from a secure +/// cryptographic hash function. +#[derive(Clone)] +#[repr(transparent)] +pub struct Hash(BytesN); + +impl Hash { + /// Constructs a new `Hash` from a fixed-length bytes array. + /// + /// This is intended for test-only, since `Hash` type is only meant to be + /// constructed via secure manners. + #[cfg(test)] + pub(crate) fn from_bytes(bytes: BytesN) -> Self { + Self(bytes) + } + + /// Returns a [`BytesN`] containing the bytes in this hash. + #[inline(always)] + pub fn to_bytes(&self) -> BytesN { + self.0.clone() + } + + /// Returns an array containing the bytes in this hash. + #[inline(always)] + pub fn to_array(&self) -> [u8; N] { + self.0.to_array() + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn as_object(&self) -> &BytesObject { + self.0.as_object() + } + + pub fn to_object(&self) -> BytesObject { + self.0.to_object() + } +} + +impl IntoVal for Hash { + fn into_val(&self, e: &Env) -> Val { + self.0.into_val(e) + } +} + +impl IntoVal> for Hash { + fn into_val(&self, _e: &Env) -> BytesN { + self.0.clone() + } +} + +impl From> for Bytes { + fn from(v: Hash) -> Self { + v.0.into() + } +} + +impl From> for BytesN { + fn from(v: Hash) -> Self { + v.0 + } +} + +impl Into<[u8; N]> for Hash { + fn into(self) -> [u8; N] { + self.0.into() + } +} + +#[allow(deprecated)] +impl crate::TryFromValForContractFn for Hash { + type Error = ConversionError; + + fn try_from_val_for_contract_fn(env: &Env, v: &Val) -> Result { + Ok(Hash(BytesN::::try_from_val(env, v)?)) + } +} + +/// Crypto provides access to cryptographic functions. +pub struct Crypto { + env: Env, +} + +impl Crypto { + pub(crate) fn new(env: &Env) -> Crypto { + Crypto { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + /// Returns the SHA-256 hash of the data. + pub fn sha256(&self, data: &Bytes) -> Hash<32> { + let env = self.env(); + let bin = internal::Env::compute_hash_sha256(env, data.into()).unwrap_infallible(); + unsafe { Hash(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Returns the Keccak-256 hash of the data. + pub fn keccak256(&self, data: &Bytes) -> Hash<32> { + let env = self.env(); + let bin = internal::Env::compute_hash_keccak256(env, data.into()).unwrap_infallible(); + unsafe { Hash(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Verifies an ed25519 signature. + /// + /// The signature is verified as a valid signature of the message by the + /// ed25519 public key. + /// + /// ### Panics + /// + /// If the signature verification fails. + pub fn ed25519_verify(&self, public_key: &BytesN<32>, message: &Bytes, signature: &BytesN<64>) { + let env = self.env(); + let _ = internal::Env::verify_sig_ed25519( + env, + public_key.to_object(), + message.to_object(), + signature.to_object(), + ); + } + + /// Recovers the ECDSA secp256k1 public key. + /// + /// The public key returned is the SEC-1-encoded ECDSA secp256k1 public key + /// that produced the 64-byte signature over a given 32-byte message digest, + /// for a given recovery_id byte. + pub fn secp256k1_recover( + &self, + message_digest: &Hash<32>, + signature: &BytesN<64>, + recovery_id: u32, + ) -> BytesN<65> { + let env = self.env(); + CryptoHazmat::new(env).secp256k1_recover(&message_digest.0, signature, recovery_id) + } + + /// Verifies the ECDSA secp256r1 signature. + /// + /// The SEC-1-encoded public key is provided along with the message, + /// verifies the 64-byte signature. + pub fn secp256r1_verify( + &self, + public_key: &BytesN<65>, + message_digest: &Hash<32>, + signature: &BytesN<64>, + ) { + let env = self.env(); + CryptoHazmat::new(env).secp256r1_verify(public_key, &message_digest.0, signature) + } + + /// Get a [Bls12_381][bls12_381::Bls12_381] for accessing the bls12-381 + /// functions. + pub fn bls12_381(&self) -> bls12_381::Bls12_381 { + bls12_381::Bls12_381::new(self.env()) + } + + /// Get a [Bn254][bn254::Bn254] for accessing the bn254 + /// functions. + pub fn bn254(&self) -> bn254::Bn254 { + bn254::Bn254::new(self.env()) + } +} + +/// # ⚠️ Hazardous Materials +/// +/// Cryptographic functions under [CryptoHazmat] are low-leveled which can be +/// insecure if misused. They are not generally recommended. Using them +/// incorrectly can introduce security vulnerabilities. Please use [Crypto] if +/// possible. +#[cfg_attr(any(test, feature = "hazmat-crypto"), visibility::make(pub))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-crypto")))] +pub(crate) struct CryptoHazmat { + env: Env, +} + +impl CryptoHazmat { + pub(crate) fn new(env: &Env) -> CryptoHazmat { + CryptoHazmat { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + /// Recovers the ECDSA secp256k1 public key. + /// + /// The public key returned is the SEC-1-encoded ECDSA secp256k1 public key + /// that produced the 64-byte signature over a given 32-byte message digest, + /// for a given recovery_id byte. + /// + /// WARNING: The `message_digest` must be produced by a secure cryptographic + /// hash function on the message, otherwise the attacker can potentially + /// forge signatures. + pub fn secp256k1_recover( + &self, + message_digest: &BytesN<32>, + signature: &BytesN<64>, + recovery_id: u32, + ) -> BytesN<65> { + let env = self.env(); + let bytes = internal::Env::recover_key_ecdsa_secp256k1( + env, + message_digest.to_object(), + signature.to_object(), + recovery_id.into(), + ) + .unwrap_infallible(); + unsafe { BytesN::unchecked_new(env.clone(), bytes) } + } + + /// Verifies the ECDSA secp256r1 signature. + /// + /// The SEC-1-encoded public key is provided along with a 32-byte message + /// digest, verifies the 64-byte signature. + /// + /// WARNING: The `message_digest` must be produced by a secure cryptographic + /// hash function on the message, otherwise the attacker can potentially + /// forge signatures. + pub fn secp256r1_verify( + &self, + public_key: &BytesN<65>, + message_digest: &BytesN<32>, + signature: &BytesN<64>, + ) { + let env = self.env(); + let _ = internal::Env::verify_sig_ecdsa_secp256r1( + env, + public_key.to_object(), + message_digest.to_object(), + signature.to_object(), + ) + .unwrap_infallible(); + } + + /// Performs a Poseidon permutation on the input state vector. + /// + /// This is a **low-level** permutation primitive. For safe, user-friendly + /// hash functions, use + /// [`rs-soroban-poseidon`](https://github.com/stellar/rs-soroban-poseidon) + /// instead, which provides input validation and standard hash constructions. + /// + /// # Field elements and `U256` + /// + /// All `U256` values (`input`, `mds`, `round_constants`) are generic + /// representations of field elements in the prime field specified by + /// `field`. If a `U256` value exceeds the field modulus, it is **silently + /// reduced mod the field order**. Two distinct `U256` inputs that reduce + /// to the same field element will produce the same output, leading to + /// unintended collisions. Callers must ensure inputs are already in the + /// valid field range. + /// + /// # Parameters + /// + /// - `input`: state vector of `t` field elements. + /// - `field`: the prime field (`"BLS12_381"` or `"BN254"`). + /// - `t`: state size (number of field elements). + /// - `d`: S-box degree (5 for BLS12-381 and BN254). + /// - `rounds_f`: number of full rounds (must be even). + /// - `rounds_p`: number of partial rounds. + /// - `mds`: `t`-by-`t` MDS matrix as `Vec>`. + /// - `round_constants`: `(rounds_f + rounds_p)`-by-`t` matrix of round + /// constants as `Vec>`. + /// + /// # Panics + /// + /// If any dimension is inconsistent or if `field` is unsupported. + pub fn poseidon_permutation( + &self, + input: &Vec, + field: Symbol, + t: u32, + d: u32, + rounds_f: u32, + rounds_p: u32, + mds: &Vec>, + round_constants: &Vec>, + ) -> Vec { + let env = self.env(); + let result = internal::Env::poseidon_permutation( + env, + input.to_object(), + field.to_symbol_val(), + t.into(), + d.into(), + rounds_f.into(), + rounds_p.into(), + mds.to_object(), + round_constants.to_object(), + ) + .unwrap_infallible(); + + result.try_into_val(env).unwrap_infallible() + } + + /// Performs a Poseidon2 permutation on the input state vector. + /// + /// This is a **low-level** permutation primitive. For safe, user-friendly + /// hash functions, use + /// [`rs-soroban-poseidon`](https://github.com/stellar/rs-soroban-poseidon) + /// instead, which provides input validation and standard hash constructions. + /// + /// # Field elements and `U256` + /// + /// All `U256` values (`input`, `mat_internal_diag_m_1`, `round_constants`) + /// are generic representations of field elements in the prime field + /// specified by `field`. If a `U256` value exceeds the field modulus, it + /// is **silently reduced mod the field order**. Two distinct `U256` inputs + /// that reduce to the same field element will produce the same output, + /// leading to unintended collisions. Callers must ensure inputs are + /// already in the valid field range. + /// + /// # Parameters + /// + /// - `input`: state vector of `t` field elements. + /// - `field`: the prime field (`"BLS12_381"` or `"BN254"`). + /// - `t`: state size (number of field elements). Only + /// `t` ∈ {2, 3, 4, 8, 12, 16, 20, 24} are supported. + /// - `d`: S-box degree (5 for BLS12-381 and BN254). + /// - `rounds_f`: number of full rounds (must be even). + /// - `rounds_p`: number of partial rounds. + /// - `mat_internal_diag_m_1`: diagonal of the internal matrix minus the + /// identity, as `Vec` of length `t`. + /// - `round_constants`: `(rounds_f + rounds_p)`-by-`t` matrix of round + /// constants as `Vec>`. + /// + /// # Panics + /// + /// If any dimension is inconsistent or if `field` is unsupported. + pub fn poseidon2_permutation( + &self, + input: &Vec, + field: Symbol, + t: u32, + d: u32, + rounds_f: u32, + rounds_p: u32, + mat_internal_diag_m_1: &Vec, + round_constants: &Vec>, + ) -> Vec { + let env = self.env(); + let result = internal::Env::poseidon2_permutation( + env, + input.to_object(), + field.to_symbol_val(), + t.into(), + d.into(), + rounds_f.into(), + rounds_p.into(), + mat_internal_diag_m_1.to_object(), + round_constants.to_object(), + ) + .unwrap_infallible(); + + result.try_into_val(env).unwrap_infallible() + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs new file mode 100644 index 0000000..1217947 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs @@ -0,0 +1,1123 @@ +#[cfg(not(target_family = "wasm"))] +use crate::xdr::ScVal; +use crate::{ + crypto::utils::BigInt, + env::internal::{self, BytesObject, U256Val, U64Val}, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, +}; +use core::{ + cmp::Ordering, + fmt::Debug, + ops::{Add, Mul, Neg, Sub}, +}; + +pub const FP_SERIALIZED_SIZE: usize = 48; // Size in bytes of a serialized Fp element in BLS12-381. The field modulus is 381 bits, requiring 48 bytes (384 bits) with 3 bits reserved for flags. +pub const FP2_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; +pub const G1_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; // Must match soroban_sdk_macro::map_type::G1_SERIALIZED_SIZE. +pub const G2_SERIALIZED_SIZE: usize = FP2_SERIALIZED_SIZE * 2; // Must match soroban_sdk_macro::map_type::G2_SERIALIZED_SIZE. + +/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381 +/// curve. +pub struct Bls12_381 { + env: Env, +} + +/// `Bls12381G1Affine` is a point in the G1 group (subgroup defined over the base field +/// `Fq`) of the BLS12-381 elliptic curve. +/// +/// This type is a thin wrapper around `BytesN<96>`. The [`from_bytes`](Self::from_bytes) +/// constructor does **not** validate the contents — it accepts any 96 bytes. +/// The serialization requirements below are enforced by the Soroban host when +/// the value is passed to a host function (e.g. `g1_add`, `g1_mul`, `pairing`). +/// Invalid bytes will cause the host call to trap, not construction. +/// +/// # Serialization: +/// - The 96 bytes represent the **uncompressed encoding** of a point in G1. The +/// Bytes consist of `be_byte(X) || be_byte(Y)` (`||` is concatenation), +/// where 'X' and 'Y' are the two coordinates, each being a base field element +/// `Fp` +/// - The most significant three bits (bits 0-3) of the first byte are reserved +/// for encoding flags: +/// - compression_flag (bit 0): Must always be unset (0), as only uncompressed +/// points are supported. +/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero +/// point), in which case all other bits must be zero. +/// - sort_flag (bit 2): Must always be unset (0). +/// +/// # Example Usage: +/// ```rust +/// use soroban_sdk::{Env, bytesn, crypto::bls12_381::{Bls12_381, Bls12381G1Affine}}; +/// let env = Env::default(); +/// let bls12_381 = env.crypto().bls12_381(); +/// let zero = Bls12381G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); +/// let one = Bls12381G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); +/// let res = bls12_381.g1_add(&zero, &one); +/// assert_eq!(res, one); +/// ``` +#[derive(Clone)] +#[repr(transparent)] +pub struct Bls12381G1Affine(BytesN); + +/// Deprecated type alias for `Bls12381G1Affine`. +/// Use the fully-qualified `Bls12381G1Affine` to avoid ambiguity with BN254 types. +#[deprecated(note = "use `Bls12381G1Affine` instead")] +pub type G1Affine = Bls12381G1Affine; + +/// `Bls12381G2Affine` is a point in the G2 group (subgroup defined over the quadratic +/// extension field `Fq2`) of the BLS12-381 elliptic curve. +/// +/// This type is a thin wrapper around `BytesN<192>`. The [`from_bytes`](Self::from_bytes) +/// constructor does **not** validate the contents — it accepts any 192 bytes. +/// The serialization requirements below are enforced by the Soroban host when +/// the value is passed to a host function (e.g. `g2_add`, `g2_mul`, `pairing`). +/// Invalid bytes will cause the host call to trap, not construction. +/// +/// # Serialization: +/// - The 192 bytes represent the **uncompressed encoding** of a point in G2. +/// The bytes consist of `be_bytes(X_c1) || be_bytes(X_c0) || be_bytes(Y_c1) +/// || be_bytes(Y_c0)` (`||` is concatenation), where 'X' and 'Y' are the two +/// coordinates, each being an extension field element `Fp2` and `c0`, `c1` +/// are components of `Fp2` (each being `Fp`). +/// - The most significant three bits (bits 0-3) of the first byte are reserved +/// for encoding flags: +/// - compression_flag (bit 0): Must always be unset (0), as only uncompressed +/// points are supported. +/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero +/// point), in which case all other bits must be zero. +/// - sort_flag (bit 2): Must always be unset (0). +#[derive(Clone)] +#[repr(transparent)] +pub struct Bls12381G2Affine(BytesN); + +/// Deprecated type alias for `Bls12381G2Affine`. +/// Use the fully-qualified `Bls12381G2Affine` to avoid ambiguity with BN254 types. +#[deprecated(note = "use `Bls12381G2Affine` instead")] +pub type G2Affine = Bls12381G2Affine; + +/// `Bls12381Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic +/// curve +/// +/// # Serialization: +/// - The 48 bytes represent the **big-endian encoding** of an element in the +/// field `Fp`. The value is serialized as a big-endian integer. +#[derive(Clone)] +#[repr(transparent)] +pub struct Bls12381Fp(BytesN); + +/// Deprecated type alias for `Bls12381Fp`. +/// Use the fully-qualified `Bls12381Fp` to avoid ambiguity with BN254 types. +#[deprecated(note = "use `Bls12381Fp` instead")] +pub type Fp = Bls12381Fp; + +/// `Bls12381Fp2` represents an element of the quadratic extension field `Fq2` of the +/// BLS12-381 elliptic curve +/// +/// # Serialization: +/// - The 96 bytes represent the **big-endian encoding** of an element in the +/// field `Fp2`. The bytes consist of `be_bytes(c1) || be_bytes(c0)` (`||` is +/// concatenation), where `c0` and `c1` are the two `Fp` elements (the real +/// and imaginary components). +#[derive(Clone)] +#[repr(transparent)] +pub struct Bls12381Fp2(BytesN); + +/// Deprecated type alias for `Bls12381Fp2`. +/// Use the fully-qualified `Bls12381Fp2` to avoid ambiguity with BN254 types. +#[deprecated(note = "use `Bls12381Fp2` instead")] +pub type Fp2 = Bls12381Fp2; + +/// `Bls12381Fr` represents an element in the BLS12-381 scalar field, which is a +/// prime field of order `r` (the order of the G1 and G2 groups). The struct is +/// internally represented with an `U256`, all arithmetic operations follow +/// modulo `r`. +#[derive(Clone)] +#[repr(transparent)] +pub struct Bls12381Fr(U256); + +/// Deprecated type alias for `Bls12381Fr`. +/// Use `Bls12381Fr` to avoid ambiguity with `Bn254Fr`. +#[deprecated(note = "use `Bls12381Fr` instead to avoid ambiguity with `Bn254Fr`")] +pub type Fr = Bls12381Fr; + +impl_bytesn_repr!(Bls12381G1Affine, G1_SERIALIZED_SIZE); +impl_bytesn_repr!(Bls12381G2Affine, G2_SERIALIZED_SIZE); +impl_bytesn_repr!(Bls12381Fp, FP_SERIALIZED_SIZE); +impl_bytesn_repr!(Bls12381Fp2, FP2_SERIALIZED_SIZE); + +// BLS12-381 base field modulus p in big-endian bytes. +// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab +const BLS12_381_FP_MODULUS_BE: [u8; FP_SERIALIZED_SIZE] = [ + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, + 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, + 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, +]; + +fn validate_fp(bytes: &[u8; FP_SERIALIZED_SIZE]) { + if bytes >= &BLS12_381_FP_MODULUS_BE { + sdk_panic!("Bls12-381: Invalid Fp"); + } +} + +fn validate_fp2(bytes: &[u8; FP2_SERIALIZED_SIZE]) { + validate_fp(bytes[0..FP_SERIALIZED_SIZE].try_into().unwrap()); + validate_fp(bytes[FP_SERIALIZED_SIZE..].try_into().unwrap()); +} + +impl Bls12381G1Affine { + /// Wraps raw bytes as a G1 point without validation. + /// See [`Bls12381G1Affine`] for serialization requirements enforced by the host. + pub fn from_bytes(bytes: BytesN) -> Self { + Self(bytes) + } +} + +impl Bls12381G2Affine { + /// Wraps raw bytes as a G2 point without validation. + /// See [`Bls12381G2Affine`] for serialization requirements enforced by the host. + pub fn from_bytes(bytes: BytesN) -> Self { + Self(bytes) + } +} + +impl Bls12381Fp { + pub fn from_bytes(bytes: BytesN) -> Self { + validate_fp(&bytes.to_array()); + Self(bytes) + } +} + +impl Bls12381Fp2 { + pub fn from_bytes(bytes: BytesN) -> Self { + validate_fp2(&bytes.to_array()); + Self(bytes) + } +} + +impl Bls12381Fp { + pub fn env(&self) -> &Env { + self.0.env() + } + + // `Bls12381Fp` represents an element in the base field of the BLS12-381 elliptic curve. + // For an element a ∈ Fp, its negation `-a` is defined as: + // a + (-a) = 0 (mod p) + // where `p` is the field modulus, and to make a valid point coordinate on the + // curve, `a` also must be within the field range (i.e., 0 ≤ a < p). + fn checked_neg(&self) -> Option { + let fp_bigint: BigInt<6> = (&self.0).into(); + if fp_bigint.is_zero() { + return Some(self.clone()); + } + + // BLS12-381 base field modulus + const BLS12_381_MODULUS: [u64; 6] = [ + 13402431016077863595, + 2210141511517208575, + 7435674573564081700, + 7239337960414712511, + 5412103778470702295, + 1873798617647539866, + ]; + let mut res = BigInt(BLS12_381_MODULUS); + + // Compute modulus - value + let borrow = res.sub_with_borrow(&fp_bigint); + if borrow { + return None; + } + + let mut bytes = [0u8; FP_SERIALIZED_SIZE]; + res.copy_into_array(&mut bytes); + Some(Bls12381Fp::from_array(self.env(), &bytes)) + } + + /// Maps this `Bls12381Fp` element to a `Bls12381G1Affine` point using the [simplified SWU + /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0). + /// + ///
+ ///
Warning
+ /// The resulting point is on the curve but may not be in the prime-order subgroup (operations + /// like pairing may fail). To ensure the point is in the prime-order subgroup, cofactor + /// clearing must be performed on the output. + /// + /// For applications requiring a point directly in the prime-order subgroup, consider using + /// `hash_to_g1`, which handles subgroup checks and cofactor clearing internally. + ///
+ pub fn map_to_g1(&self) -> Bls12381G1Affine { + self.env().crypto().bls12_381().map_fp_to_g1(self) + } +} + +impl From for BigInt<6> { + fn from(fp: Bls12381Fp) -> Self { + let inner: Bytes = fp.0.into(); + let mut limbs = [0u64; 6]; + for i in 0..6u32 { + let start = i * 8; + let mut slice = [0u8; 8]; + inner.slice(start..start + 8).copy_into_slice(&mut slice); + limbs[5 - i as usize] = u64::from_be_bytes(slice); + } + BigInt(limbs) + } +} + +impl Neg for &Bls12381Fp { + type Output = Bls12381Fp; + + fn neg(self) -> Self::Output { + match self.checked_neg() { + Some(v) => v, + None => sdk_panic!("invalid input - Bls12381Fp is larger than the field modulus"), + } + } +} + +impl Neg for Bls12381Fp { + type Output = Bls12381Fp; + + fn neg(self) -> Self::Output { + (&self).neg() + } +} + +impl Bls12381G1Affine { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn is_in_subgroup(&self) -> bool { + self.env().crypto().bls12_381().g1_is_in_subgroup(self) + } + + pub fn checked_add(&self, rhs: &Self) -> Option { + self.env().crypto().bls12_381().g1_checked_add(self, rhs) + } +} + +impl Add for Bls12381G1Affine { + type Output = Bls12381G1Affine; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().g1_add(&self, &rhs) + } +} + +impl Mul for Bls12381G1Affine { + type Output = Bls12381G1Affine; + + fn mul(self, rhs: Bls12381Fr) -> Self::Output { + self.env().crypto().bls12_381().g1_mul(&self, &rhs) + } +} + +// Bls12381G1Affine represents a point (X, Y) on the BLS12-381 curve where X, Y ∈ Bls12381Fp +// Negation of (X, Y) is defined as (X, -Y) +impl Neg for &Bls12381G1Affine { + type Output = Bls12381G1Affine; + + fn neg(self) -> Self::Output { + let mut inner: Bytes = (&self.0).into(); + let y = Bls12381Fp::try_from_val( + inner.env(), + inner.slice(FP_SERIALIZED_SIZE as u32..).as_val(), + ) + .unwrap_optimized(); + let neg_y = -y; + inner.copy_from_slice(FP_SERIALIZED_SIZE as u32, &neg_y.to_array()); + Bls12381G1Affine::from_bytes( + BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(), + ) + } +} + +impl Neg for Bls12381G1Affine { + type Output = Bls12381G1Affine; + + fn neg(self) -> Self::Output { + (&self).neg() + } +} + +impl Bls12381Fp2 { + pub fn env(&self) -> &Env { + self.0.env() + } + + // An Bls12381Fp2 element is represented as c0 + c1 * X, where: + // - c0, c1 are base field elements (Bls12381Fp) + // - X is the quadratic non-residue used to construct the field extension + // The negation of c0 + c1 * X is (-c0) + (-c1) * X. + fn checked_neg(&self) -> Option { + let mut inner = self.to_array(); + let mut slice0 = [0; FP_SERIALIZED_SIZE]; + let mut slice1 = [0; FP_SERIALIZED_SIZE]; + slice0.copy_from_slice(&inner[0..FP_SERIALIZED_SIZE]); + slice1.copy_from_slice(&inner[FP_SERIALIZED_SIZE..FP2_SERIALIZED_SIZE]); + + // Convert both components to Bls12381Fp and negate them + let c0 = Bls12381Fp::from_array(self.env(), &slice0); + let c1 = Bls12381Fp::from_array(self.env(), &slice1); + + // If either component's negation fails, the whole operation fails + let neg_c0 = c0.checked_neg()?; + let neg_c1 = c1.checked_neg()?; + + // Reconstruct the Bls12381Fp2 element from negated components + inner[0..FP_SERIALIZED_SIZE].copy_from_slice(&neg_c0.to_array()); + inner[FP_SERIALIZED_SIZE..FP2_SERIALIZED_SIZE].copy_from_slice(&neg_c1.to_array()); + + Some(Bls12381Fp2::from_array(self.env(), &inner)) + } + + /// Maps this `Bls12381Fp2` element to a `Bls12381G2Affine` point using the [simplified SWU + /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0). + /// + ///
+ ///
Warning
+ /// The resulting point is on the curve but may not be in the prime-order subgroup (operations + /// like pairing may fail). To ensure the point is in the prime-order subgroup, cofactor + /// clearing must be performed on the output. + /// + /// For applications requiring a point directly in the prime-order subgroup, consider using + /// `hash_to_g2`, which handles subgroup checks and cofactor clearing internally. + ///
+ pub fn map_to_g2(&self) -> Bls12381G2Affine { + self.env().crypto().bls12_381().map_fp2_to_g2(self) + } +} + +impl Neg for &Bls12381Fp2 { + type Output = Bls12381Fp2; + + fn neg(self) -> Self::Output { + match self.checked_neg() { + Some(v) => v, + None => { + sdk_panic!("invalid input - Bls12381Fp2 component is larger than the field modulus") + } + } + } +} + +impl Neg for Bls12381Fp2 { + type Output = Bls12381Fp2; + + fn neg(self) -> Self::Output { + (&self).neg() + } +} + +impl Bls12381G2Affine { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn is_in_subgroup(&self) -> bool { + self.env().crypto().bls12_381().g2_is_in_subgroup(self) + } + + pub fn checked_add(&self, rhs: &Self) -> Option { + self.env().crypto().bls12_381().g2_checked_add(self, rhs) + } +} + +impl Add for Bls12381G2Affine { + type Output = Bls12381G2Affine; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().g2_add(&self, &rhs) + } +} + +impl Mul for Bls12381G2Affine { + type Output = Bls12381G2Affine; + + fn mul(self, rhs: Bls12381Fr) -> Self::Output { + self.env().crypto().bls12_381().g2_mul(&self, &rhs) + } +} + +// Bls12381G2Affine represents a point (X, Y) on the BLS12-381 quadratic extension curve where X, Y ∈ Bls12381Fp2 +// Negation of (X, Y) is defined as (X, -Y) +impl Neg for &Bls12381G2Affine { + type Output = Bls12381G2Affine; + + fn neg(self) -> Self::Output { + let mut inner: Bytes = (&self.0).into(); + let y = Bls12381Fp2::try_from_val( + inner.env(), + inner.slice(FP2_SERIALIZED_SIZE as u32..).as_val(), + ) + .unwrap_optimized(); + let neg_y = -y; + inner.copy_from_slice(FP2_SERIALIZED_SIZE as u32, &neg_y.to_array()); + Bls12381G2Affine::from_bytes( + BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(), + ) + } +} + +impl Neg for Bls12381G2Affine { + type Output = Bls12381G2Affine; + + fn neg(self) -> Self::Output { + (&self).neg() + } +} + +impl Bls12381Fr { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn from_u256(value: U256) -> Self { + value.into() + } + + pub fn to_u256(&self) -> U256 { + self.0.clone() + } + + pub fn as_u256(&self) -> &U256 { + &self.0 + } + + pub fn from_bytes(bytes: BytesN<32>) -> Self { + U256::from_be_bytes(bytes.env(), bytes.as_ref()).into() + } + + pub fn to_bytes(&self) -> BytesN<32> { + self.as_u256().to_be_bytes().try_into().unwrap_optimized() + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn pow(&self, rhs: u64) -> Self { + self.env().crypto().bls12_381().fr_pow(self, rhs) + } + + pub fn inv(&self) -> Self { + self.env().crypto().bls12_381().fr_inv(self) + } +} + +// BLS12-381 scalar field modulus r in big-endian bytes. +// r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +const BLS12_381_FR_MODULUS_BE: [u8; 32] = [ + 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05, + 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, +]; + +fn fr_modulus(env: &Env) -> U256 { + U256::from_be_bytes(env, &Bytes::from_array(env, &BLS12_381_FR_MODULUS_BE)) +} + +impl From for Bls12381Fr { + fn from(value: U256) -> Self { + // Keep all Fr construction paths canonical by reducing modulo r here. + // Constructors and deserialization paths should route through this impl. + // Skip the expensive rem_euclid when value is already canonical (< r), + // which is always the case for host-returned arithmetic results. + let modulus = fr_modulus(value.env()); + if value >= modulus { + Self(value.rem_euclid(&modulus)) + } else { + Self(value) + } + } +} + +impl From<&Bls12381Fr> for U256Val { + fn from(value: &Bls12381Fr) -> Self { + value.as_u256().into() + } +} + +impl TryFromVal for Bls12381Fr { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + let u = U256::try_from_val(env, val)?; + Ok(u.into()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, fr: &Bls12381Fr) -> Result { + Ok(fr.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, fr: &&Bls12381Fr) -> Result { + Ok(fr.to_val()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Bls12381Fr> for ScVal { + fn from(v: &Bls12381Fr) -> Self { + Self::from(&v.0) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for ScVal { + fn from(v: Bls12381Fr) -> Self { + (&v).into() + } +} + +impl Eq for Bls12381Fr {} + +impl PartialEq for Bls12381Fr { + fn eq(&self, other: &Self) -> bool { + self.as_u256().partial_cmp(other.as_u256()) == Some(Ordering::Equal) + } +} + +impl Debug for Bls12381Fr { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Bls12381Fr({:?})", self.as_u256()) + } +} + +impl Add for Bls12381Fr { + type Output = Bls12381Fr; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().fr_add(&self, &rhs) + } +} + +impl Sub for Bls12381Fr { + type Output = Bls12381Fr; + + fn sub(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().fr_sub(&self, &rhs) + } +} + +impl Mul for Bls12381Fr { + type Output = Bls12381Fr; + + fn mul(self, rhs: Self) -> Self::Output { + self.env().crypto().bls12_381().fr_mul(&self, &rhs) + } +} + +impl Bls12_381 { + pub(crate) fn new(env: &Env) -> Bls12_381 { + Bls12_381 { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + // g1 + + /// Checks if a point `p` in G1 is in the correct subgroup. + pub fn g1_is_in_subgroup(&self, p: &Bls12381G1Affine) -> bool { + let env = self.env(); + let res = internal::Env::bls12_381_check_g1_is_in_subgroup(env, p.to_object()) + .unwrap_infallible(); + res.into() + } + + /// Checks if a G1 point is on the BLS12-381 curve (no subgroup check). + pub fn g1_is_on_curve(&self, point: &Bls12381G1Affine) -> bool { + let env = self.env(); + internal::Env::bls12_381_g1_is_on_curve(env, point.to_object()) + .unwrap_infallible() + .into() + } + + /// Adds two points `p0` and `p1` in G1. + pub fn g1_add(&self, p0: &Bls12381G1Affine, p1: &Bls12381G1Affine) -> Bls12381G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the + /// correct subgroup. Note the subgroup check is computationally expensive, + /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. + pn`, + /// it may make sense to only call g1_checked_add on the final addition, + /// while using `g1_add` (non-checked version) on the intermediate ones. + pub fn g1_checked_add( + &self, + p0: &Bls12381G1Affine, + p1: &Bls12381G1Affine, + ) -> Option { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + let res = unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }; + let is_in_correct_subgroup: bool = + internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) + .unwrap_optimized() + .into(); + match is_in_correct_subgroup { + true => Some(res), + false => None, + } + } + + /// Multiplies a point `p0` in G1 by a scalar. + pub fn g1_mul(&self, p0: &Bls12381G1Affine, scalar: &Bls12381Fr) -> Bls12381G1Affine { + let env = self.env(); + let bin = + internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Performs a multi-scalar multiplication (MSM) operation in G1. + pub fn g1_msm(&self, vp: Vec, vs: Vec) -> Bls12381G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); + unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Maps an element in the base field `Bls12381Fp` to a point in G1. + pub fn map_fp_to_g1(&self, fp: &Bls12381Fp) -> Bls12381G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); + unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. + pub fn hash_to_g1(&self, msg: &Bytes, dst: &Bytes) -> Bls12381G1Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) + .unwrap_infallible(); + unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + // g2 + + /// Checks if a point `p` in G2 is in the correct subgroup. + pub fn g2_is_in_subgroup(&self, p: &Bls12381G2Affine) -> bool { + let env = self.env(); + let res = internal::Env::bls12_381_check_g2_is_in_subgroup(env, p.to_object()) + .unwrap_infallible(); + res.into() + } + + /// Checks if a G2 point is on the BLS12-381 curve (no subgroup check). + pub fn g2_is_on_curve(&self, point: &Bls12381G2Affine) -> bool { + let env = self.env(); + internal::Env::bls12_381_g2_is_on_curve(env, point.to_object()) + .unwrap_infallible() + .into() + } + + /// Adds two points `p0` and `p1` in G2. + pub fn g2_add(&self, p0: &Bls12381G2Affine, p1: &Bls12381G2Affine) -> Bls12381G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the + /// correct subgroup. Note the subgroup check is computationally expensive, + /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. +pn`, + /// it may make sense to only call g2_checked_add on the final addition, + /// while using `g2_add` (non-checked version) on the intermediate ones. + pub fn g2_checked_add( + &self, + p0: &Bls12381G2Affine, + p1: &Bls12381G2Affine, + ) -> Option { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) + .unwrap_infallible(); + let res = unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }; + let is_in_correct_subgroup: bool = + internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) + .unwrap_optimized() + .into(); + match is_in_correct_subgroup { + true => Some(res), + false => None, + } + } + + /// Multiplies a point `p0` in G2 by a scalar. + pub fn g2_mul(&self, p0: &Bls12381G2Affine, scalar: &Bls12381Fr) -> Bls12381G2Affine { + let env = self.env(); + let bin = + internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Performs a multi-scalar multiplication (MSM) operation in G2. + pub fn g2_msm(&self, vp: Vec, vs: Vec) -> Bls12381G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); + unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Maps an element in the base field `Bls12381Fp2` to a point in G2. + pub fn map_fp2_to_g2(&self, fp2: &Bls12381Fp2) -> Bls12381G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); + unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. + pub fn hash_to_g2(&self, msg: &Bytes, dst: &Bytes) -> Bls12381G2Affine { + let env = self.env(); + let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) + .unwrap_infallible(); + unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + // pairing + + /// Performs a pairing check between vectors of points in G1 and G2. + /// + /// This function computes the pairing for each pair of points in the + /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if + /// the overall pairing result is equal to the identity in the target group. + /// + /// # Returns: + /// - `true` if the pairing check holds (i.e., the pairing result is valid + /// and equal to the identity element), otherwise `false`. + /// + /// # Panics: + /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. + pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { + let env = self.env(); + internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into()) + .unwrap_infallible() + .into() + } + + // scalar arithmetic + + /// Adds two scalars in the BLS12-381 scalar field `Bls12381Fr`. + pub fn fr_add(&self, lhs: &Bls12381Fr, rhs: &Bls12381Fr) -> Bls12381Fr { + let env = self.env(); + let v = internal::Env::bls12_381_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Subtracts one scalar from another in the BLS12-381 scalar field `Bls12381Fr`. + pub fn fr_sub(&self, lhs: &Bls12381Fr, rhs: &Bls12381Fr) -> Bls12381Fr { + let env = self.env(); + let v = internal::Env::bls12_381_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Multiplies two scalars in the BLS12-381 scalar field `Bls12381Fr`. + pub fn fr_mul(&self, lhs: &Bls12381Fr, rhs: &Bls12381Fr) -> Bls12381Fr { + let env = self.env(); + let v = internal::Env::bls12_381_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Raises a scalar to the power of a given exponent in the BLS12-381 scalar field `Bls12381Fr`. + pub fn fr_pow(&self, lhs: &Bls12381Fr, rhs: u64) -> Bls12381Fr { + let env = self.env(); + let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); + let v = internal::Env::bls12_381_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Computes the multiplicative inverse of a scalar in the BLS12-381 scalar field `Bls12381Fr`. + pub fn fr_inv(&self, lhs: &Bls12381Fr) -> Bls12381Fr { + let env = self.env(); + let v = internal::Env::bls12_381_fr_inv(env, lhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_g1affine_to_val() { + let env = Env::default(); + + let g1 = Bls12381G1Affine::from_bytes(BytesN::from_array(&env, &[1; 96])); + let val: Val = g1.clone().into_val(&env); + let rt: Bls12381G1Affine = val.into_val(&env); + + assert_eq!(g1, rt); + } + + #[test] + fn test_ref_g1affine_to_val() { + let env = Env::default(); + + let g1 = Bls12381G1Affine::from_bytes(BytesN::from_array(&env, &[1; 96])); + let val: Val = (&g1).into_val(&env); + let rt: Bls12381G1Affine = val.into_val(&env); + + assert_eq!(g1, rt); + } + + #[test] + fn test_doule_ref_g1affine_to_val() { + let env = Env::default(); + + let g1 = Bls12381G1Affine::from_bytes(BytesN::from_array(&env, &[1; 96])); + let val: Val = (&&g1).into_val(&env); + let rt: Bls12381G1Affine = val.into_val(&env); + + assert_eq!(g1, rt); + } + + #[test] + fn test_fr_to_val() { + let env = Env::default(); + + let fr = Bls12381Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); + let val: Val = fr.clone().into_val(&env); + let rt: Bls12381Fr = val.into_val(&env); + + assert_eq!(fr, rt); + } + + #[test] + fn test_ref_fr_to_val() { + let env = Env::default(); + + let fr = Bls12381Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); + let val: Val = (&fr).into_val(&env); + let rt: Bls12381Fr = val.into_val(&env); + + assert_eq!(fr, rt); + } + + #[test] + fn test_double_ref_fr_to_val() { + let env = Env::default(); + + let fr = Bls12381Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); + let val: Val = (&&fr).into_val(&env); + let rt: Bls12381Fr = val.into_val(&env); + + assert_eq!(fr, rt); + } + + #[test] + fn test_fr_eq_both_unreduced() { + let env = Env::default(); + let r = fr_modulus(&env); + let one = U256::from_u32(&env, 1); + + let a = Bls12381Fr::from_u256(r.add(&one)); + let b = Bls12381Fr::from_u256(one.clone()); + assert_eq!(a, b); + + let two_r_plus_one = r.add(&r).add(&one); + let c = Bls12381Fr::from_u256(two_r_plus_one); + assert_eq!(a, c); + assert_eq!(b, c); + } + + #[test] + fn test_fr_eq_unreduced_vs_zero() { + let env = Env::default(); + let r = fr_modulus(&env); + let zero = U256::from_u32(&env, 0); + + let a = Bls12381Fr::from_u256(r); + let b = Bls12381Fr::from_u256(zero); + assert_eq!(a, b); + } + + #[test] + fn test_fr_reduced_value_unchanged() { + let env = Env::default(); + let r = fr_modulus(&env); + let val = r.sub(&U256::from_u32(&env, 1)); + + let fr = Bls12381Fr::from_u256(val.clone()); + assert_eq!(fr.to_u256(), val); + + let fr42 = Bls12381Fr::from_u256(U256::from_u32(&env, 42)); + assert_eq!(fr42.to_u256(), U256::from_u32(&env, 42)); + } + + #[test] + fn test_fr_from_bytes_reduces() { + let env = Env::default(); + let one_fr = Bls12381Fr::from_u256(U256::from_u32(&env, 1)); + + // BLS12-381 r+1 as big-endian bytes + let fr_from_bytes = Bls12381Fr::from_bytes(bytesn!( + &env, + 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002 + )); + assert_eq!(fr_from_bytes, one_fr); + } + + #[test] + fn test_fr_try_from_val_reduces() { + let env = Env::default(); + let r = fr_modulus(&env); + let one = U256::from_u32(&env, 1); + + let unreduced_u256 = r.add(&one); + let val: Val = unreduced_u256.into_val(&env); + let fr_from_val: Bls12381Fr = val.into_val(&env); + let fr_one = Bls12381Fr::from_u256(one); + assert_eq!(fr_from_val, fr_one); + } + + #[test] + fn test_fr_u256_into_reduces() { + // Direct From::from / .into() path must reduce + let env = Env::default(); + let r = fr_modulus(&env); + let one = U256::from_u32(&env, 1); + + let fr: Bls12381Fr = r.add(&one).into(); // r+1 via .into() + let fr_one: Bls12381Fr = one.into(); + assert_eq!(fr, fr_one); + } + + #[test] + fn test_fr_eq_unreduced_vs_host_computed() { + // User-provided unreduced Fr vs host-computed Fr + let env = Env::default(); + let bls = Bls12_381::new(&env); + let r = fr_modulus(&env); + let five = U256::from_u32(&env, 5); + + // User provides r+5 (unreduced) + let user_fr = Bls12381Fr::from_u256(r.add(&five)); + // Host computes 2+3 = 5 (always reduced) + let host_fr = bls.fr_add( + &Bls12381Fr::from_u256(U256::from_u32(&env, 2)), + &Bls12381Fr::from_u256(U256::from_u32(&env, 3)), + ); + assert_eq!(user_fr, host_fr); + } + + // Fp validation tests + + #[test] + fn test_fp_max_valid_accepted() { + let env = Env::default(); + // p - 1 (last byte 0xaa instead of 0xab) + let mut p_minus_1 = BLS12_381_FP_MODULUS_BE; + p_minus_1[FP_SERIALIZED_SIZE - 1] -= 1; + let _ = Bls12381Fp::from_array(&env, &p_minus_1); + } + + #[test] + #[should_panic(expected = "Bls12-381: Invalid Fp")] + fn test_fp_at_modulus_panics() { + let env = Env::default(); + let _ = Bls12381Fp::from_array(&env, &BLS12_381_FP_MODULUS_BE); + } + + #[test] + #[should_panic(expected = "Bls12-381: Invalid Fp")] + fn test_fp_above_modulus_panics() { + let env = Env::default(); + let mut above = BLS12_381_FP_MODULUS_BE; + above[FP_SERIALIZED_SIZE - 1] += 1; // p + 1 + let _ = Bls12381Fp::from_array(&env, &above); + } + + #[test] + fn test_fp_from_bytes_validates() { + let env = Env::default(); + // Zero should be valid + let _ = Bls12381Fp::from_bytes(BytesN::from_array(&env, &[0u8; FP_SERIALIZED_SIZE])); + } + + #[test] + #[should_panic(expected = "Bls12-381: Invalid Fp")] + fn test_fp_from_bytes_rejects_modulus() { + let env = Env::default(); + let _ = Bls12381Fp::from_bytes(BytesN::from_array(&env, &BLS12_381_FP_MODULUS_BE)); + } + + #[test] + #[should_panic(expected = "Bls12-381: Invalid Fp")] + fn test_fp_try_from_val_rejects_modulus() { + let env = Env::default(); + let bytes = BytesN::from_array(&env, &BLS12_381_FP_MODULUS_BE); + let val: Val = bytes.into_val(&env); + let _: Bls12381Fp = val.into_val(&env); + } + + #[test] + #[should_panic(expected = "Bls12-381: Invalid Fp")] + fn test_fp2_component_above_modulus_panics() { + let env = Env::default(); + // First Fp component is the modulus (invalid), second is zero (valid) + let mut fp2_bytes = [0u8; FP2_SERIALIZED_SIZE]; + fp2_bytes[0..FP_SERIALIZED_SIZE].copy_from_slice(&BLS12_381_FP_MODULUS_BE); + let _ = Bls12381Fp2::from_array(&env, &fp2_bytes); + } + + #[test] + #[should_panic(expected = "Bls12-381: Invalid Fp")] + fn test_fp2_second_component_above_modulus_panics() { + let env = Env::default(); + // First Fp component is zero (valid), second is the modulus (invalid) + let mut fp2_bytes = [0u8; FP2_SERIALIZED_SIZE]; + fp2_bytes[FP_SERIALIZED_SIZE..].copy_from_slice(&BLS12_381_FP_MODULUS_BE); + let _ = Bls12381Fp2::from_array(&env, &fp2_bytes); + } + + #[test] + fn test_fp2_max_valid_accepted() { + let env = Env::default(); + // Both components are p-1 (valid) + let mut p_minus_1 = BLS12_381_FP_MODULUS_BE; + p_minus_1[FP_SERIALIZED_SIZE - 1] -= 1; + let mut fp2_bytes = [0u8; FP2_SERIALIZED_SIZE]; + fp2_bytes[0..FP_SERIALIZED_SIZE].copy_from_slice(&p_minus_1); + fp2_bytes[FP_SERIALIZED_SIZE..].copy_from_slice(&p_minus_1); + let _ = Bls12381Fp2::from_array(&env, &fp2_bytes); + } + + #[test] + fn test_bls12_381_fp_modulus_matches_arkworks() { + use ark_bls12_381::Fq; + use ark_ff::{BigInteger, PrimeField}; + + let be_bytes = Fq::MODULUS.to_bytes_be(); + assert_eq!( + be_bytes.as_slice(), + &BLS12_381_FP_MODULUS_BE, + "BLS12-381 Fp modulus does not match arkworks" + ); + } + + #[test] + fn test_bls12_381_fr_modulus_matches_arkworks() { + use ark_bls12_381::Fr as ArkFr; + use ark_ff::{BigInteger, PrimeField}; + + let be_bytes = ArkFr::MODULUS.to_bytes_be(); + assert_eq!( + be_bytes.as_slice(), + &BLS12_381_FR_MODULUS_BE, + "BLS12-381 Fr modulus does not match arkworks" + ); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs new file mode 100644 index 0000000..6185700 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs @@ -0,0 +1,727 @@ +#[cfg(not(target_family = "wasm"))] +use crate::xdr::ScVal; +use crate::{ + crypto::utils::BigInt, + env::internal::{self, BytesObject, U256Val, U64Val}, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, +}; +use core::{ + cmp::Ordering, + fmt::Debug, + ops::{Add, Mul, Neg, Sub}, +}; + +pub const BN254_FP_SERIALIZED_SIZE: usize = 32; // Size in bytes of a serialized Bn254Fp element in BN254. The field modulus is 254 bits, requiring 32 bytes (256 bits). +pub const BN254_G1_SERIALIZED_SIZE: usize = BN254_FP_SERIALIZED_SIZE * 2; // Size in bytes of a serialized G1 element in BN254. Each coordinate (X, Y) is 32 bytes. +pub const BN254_G2_SERIALIZED_SIZE: usize = BN254_G1_SERIALIZED_SIZE * 2; // Size in bytes of a serialized G2 element in BN254. Each coordinate (X, Y) is 64 bytes (2 Bn254Fp elements per coordinate). + +/// Bn254 provides access to curve and pairing operations on the BN254 +/// (also known as alt_bn128) curve. +pub struct Bn254 { + env: Env, +} + +/// `Bn254G1Affine` is a point in the G1 group (subgroup defined over the base field +/// `Fq` with prime order `q = +/// 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47`) of the +/// BN254 elliptic curve. +/// +/// This type is a thin wrapper around `BytesN<64>`. The [`from_bytes`](Self::from_bytes) +/// constructor does **not** validate the contents — it accepts any 64 bytes. +/// The serialization requirements below are enforced by the Soroban host when +/// the value is passed to a host function (e.g. `g1_add`, `g1_mul`, `pairing`). +/// Invalid bytes will cause the host call to trap, not construction. +/// +/// # Serialization (Ethereum-compatible format): +/// - The 64 bytes represent the **uncompressed encoding** of a point in G1 +/// - Format: `be_bytes(X) || be_bytes(Y)` where `||` denotes concatenation +/// - X and Y are curve coordinates, each a 32-byte big-endian Bn254Fp field element +/// - The two flag bits (bits 0x80 and 0x40 of the first byte) must be unset +/// - The point at infinity is encoded as 64 zero bytes +/// - Points must be on the curve (no subgroup check required for G1) +#[derive(Clone)] +#[repr(transparent)] +pub struct Bn254G1Affine(BytesN); + +/// `Bn254G2Affine` is a point in the G2 group (subgroup defined over the quadratic +/// extension field `Fq2`) of the BN254 elliptic curve. +/// +/// This type is a thin wrapper around `BytesN<128>`. The [`from_bytes`](Self::from_bytes) +/// constructor does **not** validate the contents — it accepts any 128 bytes. +/// The serialization requirements below are enforced by the Soroban host when +/// the value is passed to a host function (e.g. `g2_add`, `g2_mul`, `pairing`). +/// Invalid bytes will cause the host call to trap, not construction. +/// +/// # Serialization (Ethereum-compatible format): +/// - The 128 bytes represent the **uncompressed encoding** of a point in G2 +/// - Format: `be_bytes(X) || be_bytes(Y)` where each coordinate is an Fp2 +/// element (64 bytes) - Fp2 element encoding: `be_bytes(c1) || be_bytes(c0)` +/// where: +/// - c0 is the real component (32-byte big-endian Bn254Fp element) +/// - c1 is the imaginary component (32-byte big-endian Bn254Fp element) +/// - The two flag bits (bits 0x80 and 0x40 of the first byte) must be unset +/// - The point at infinity is encoded as 128 zero bytes +/// - Points must be on the curve AND in the correct subgroup +#[derive(Clone)] +#[repr(transparent)] +pub struct Bn254G2Affine(BytesN); + +/// `Bn254Fr` represents an element in the BN254 scalar field, which is a prime +/// field of order `r = +/// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001`. The +/// struct is internally represented with a `U256`, all arithmetic operations +/// follow modulo `r`. +#[derive(Clone)] +#[repr(transparent)] +pub struct Bn254Fr(U256); + +/// Deprecated type alias for `Bn254Fr`. +/// Use `Bn254Fr` to avoid ambiguity with `Bls12381Fr`. +#[deprecated(note = "use `Bn254Fr` instead to avoid ambiguity with `Bls12381Fr`")] +pub type Fr = Bn254Fr; + +/// `Bn254Fp` represents an element of the base field `Bn254Fp` of the BN254 elliptic curve +/// +/// # Serialization: +/// - The 32 bytes represent the **big-endian encoding** of an element in the +/// field `Bn254Fp`. The value is serialized as a big-endian integer. +#[derive(Clone)] +#[repr(transparent)] +pub struct Bn254Fp(BytesN); + +impl_bytesn_repr!(Bn254G1Affine, BN254_G1_SERIALIZED_SIZE); +impl_bytesn_repr!(Bn254G2Affine, BN254_G2_SERIALIZED_SIZE); +impl_bytesn_repr!(Bn254Fp, BN254_FP_SERIALIZED_SIZE); + +// BN254 base field modulus p in big-endian bytes. +// p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 +const BN254_FP_MODULUS_BE: [u8; BN254_FP_SERIALIZED_SIZE] = [ + 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, 0x58, 0x5d, + 0x97, 0x81, 0x6a, 0x91, 0x68, 0x71, 0xca, 0x8d, 0x3c, 0x20, 0x8c, 0x16, 0xd8, 0x7c, 0xfd, 0x47, +]; + +fn validate_bn254_fp(bytes: &[u8; BN254_FP_SERIALIZED_SIZE]) { + if bytes >= &BN254_FP_MODULUS_BE { + sdk_panic!("Bn254: Invalid Fp"); + } +} + +impl Bn254G1Affine { + /// Wraps raw bytes as a G1 point without validation. + /// See [`Bn254G1Affine`] for serialization requirements enforced by the host. + pub fn from_bytes(bytes: BytesN) -> Self { + Self(bytes) + } +} + +impl Bn254G2Affine { + /// Wraps raw bytes as a G2 point without validation. + /// See [`Bn254G2Affine`] for serialization requirements enforced by the host. + pub fn from_bytes(bytes: BytesN) -> Self { + Self(bytes) + } +} + +impl Bn254Fp { + pub fn from_bytes(bytes: BytesN) -> Self { + validate_bn254_fp(&bytes.to_array()); + Self(bytes) + } +} + +impl Bn254G1Affine { + pub fn env(&self) -> &Env { + self.0.env() + } +} + +impl Bn254Fp { + pub fn env(&self) -> &Env { + self.0.env() + } + + // `Bn254Fp` represents an element in the base field of the BN254 elliptic curve. + // For an element a ∈ Bn254Fp, its negation `-a` is defined as: + // a + (-a) = 0 (mod p) + // where `p` is the field modulus, and to make a valid point coordinate on the + // curve, `a` also must be within the field range (i.e., 0 ≤ a < p). + fn checked_neg(&self) -> Option { + let fq_bigint: BigInt<4> = (&self.0).into(); + if fq_bigint.is_zero() { + return Some(self.clone()); + } + + //BN254 base field modulus + const BN254_MODULUS: [u64; 4] = [ + 4332616871279656263, + 10917124144477883021, + 13281191951274694749, + 3486998266802970665, + ]; + let mut res = BigInt(BN254_MODULUS); + + // Compute modulus - value + let borrow = res.sub_with_borrow(&fq_bigint); + if borrow { + return None; + } + + let mut bytes = [0u8; BN254_FP_SERIALIZED_SIZE]; + res.copy_into_array(&mut bytes); + Some(Bn254Fp::from_array(self.env(), &bytes)) + } +} + +impl Neg for &Bn254Fp { + type Output = Bn254Fp; + + fn neg(self) -> Self::Output { + match self.checked_neg() { + Some(v) => v, + None => sdk_panic!("invalid input - Bn254Fp is larger than the field modulus"), + } + } +} + +impl Neg for Bn254Fp { + type Output = Bn254Fp; + + fn neg(self) -> Self::Output { + (&self).neg() + } +} + +impl Add for Bn254G1Affine { + type Output = Bn254G1Affine; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bn254().g1_add(&self, &rhs) + } +} + +impl Mul for Bn254G1Affine { + type Output = Bn254G1Affine; + + fn mul(self, rhs: Bn254Fr) -> Self::Output { + self.env().crypto().bn254().g1_mul(&self, &rhs) + } +} + +// Bn254G1Affine represents a point (X, Y) on the BN254 curve where X, Y ∈ Bn254Fp +// Negation of (X, Y) is defined as (X, -Y) +impl Neg for &Bn254G1Affine { + type Output = Bn254G1Affine; + + fn neg(self) -> Self::Output { + let mut inner: Bytes = (&self.0).into(); + let y = Bn254Fp::try_from_val( + inner.env(), + inner.slice(BN254_FP_SERIALIZED_SIZE as u32..).as_val(), + ) + .unwrap_optimized(); + let neg_y = -y; + inner.copy_from_slice(BN254_FP_SERIALIZED_SIZE as u32, &neg_y.to_array()); + Bn254G1Affine::from_bytes( + BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(), + ) + } +} + +impl Neg for Bn254G1Affine { + type Output = Bn254G1Affine; + + fn neg(self) -> Self::Output { + (&self).neg() + } +} + +impl Bn254G2Affine { + pub fn env(&self) -> &Env { + self.0.env() + } +} + +impl Bn254Fr { + pub fn env(&self) -> &Env { + self.0.env() + } + + pub fn from_u256(value: U256) -> Self { + value.into() + } + + pub fn to_u256(&self) -> U256 { + self.0.clone() + } + + pub fn as_u256(&self) -> &U256 { + &self.0 + } + + pub fn from_bytes(bytes: BytesN<32>) -> Self { + U256::from_be_bytes(bytes.env(), bytes.as_ref()).into() + } + + pub fn to_bytes(&self) -> BytesN<32> { + self.as_u256().to_be_bytes().try_into().unwrap_optimized() + } + + pub fn as_val(&self) -> &Val { + self.0.as_val() + } + + pub fn to_val(&self) -> Val { + self.0.to_val() + } + + pub fn pow(&self, rhs: u64) -> Self { + self.env().crypto().bn254().fr_pow(self, rhs) + } + + pub fn inv(&self) -> Self { + self.env().crypto().bn254().fr_inv(self) + } +} + +impl Add for Bn254Fr { + type Output = Bn254Fr; + + fn add(self, rhs: Self) -> Self::Output { + self.env().crypto().bn254().fr_add(&self, &rhs) + } +} + +impl Sub for Bn254Fr { + type Output = Bn254Fr; + + fn sub(self, rhs: Self) -> Self::Output { + self.env().crypto().bn254().fr_sub(&self, &rhs) + } +} + +impl Mul for Bn254Fr { + type Output = Bn254Fr; + + fn mul(self, rhs: Self) -> Self::Output { + self.env().crypto().bn254().fr_mul(&self, &rhs) + } +} + +// BN254 scalar field modulus r in big-endian bytes. +// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +const BN254_FR_MODULUS_BE: [u8; 32] = [ + 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, 0x58, 0x5d, + 0x28, 0x33, 0xe8, 0x48, 0x79, 0xb9, 0x70, 0x91, 0x43, 0xe1, 0xf5, 0x93, 0xf0, 0x00, 0x00, 0x01, +]; + +fn fr_modulus(env: &Env) -> U256 { + U256::from_be_bytes(env, &Bytes::from_array(env, &BN254_FR_MODULUS_BE)) +} + +impl From for Bn254Fr { + fn from(value: U256) -> Self { + // Keep all Bn254Fr construction paths canonical by reducing modulo r here. + // Constructors and deserialization paths should route through this impl. + // Skip the expensive rem_euclid when value is already canonical (< r), + // which is always the case for host-returned arithmetic results. + let modulus = fr_modulus(value.env()); + if value >= modulus { + Self(value.rem_euclid(&modulus)) + } else { + Self(value) + } + } +} + +impl From<&Bn254Fr> for U256Val { + fn from(value: &Bn254Fr) -> Self { + value.as_u256().into() + } +} + +impl TryFromVal for Bn254Fr { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + let u = U256::try_from_val(env, val)?; + Ok(u.into()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, fr: &Bn254Fr) -> Result { + Ok(fr.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, fr: &&Bn254Fr) -> Result { + Ok(fr.to_val()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Bn254Fr> for ScVal { + fn from(v: &Bn254Fr) -> Self { + Self::from(&v.0) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for ScVal { + fn from(v: Bn254Fr) -> Self { + (&v).into() + } +} + +impl Eq for Bn254Fr {} + +impl PartialEq for Bn254Fr { + fn eq(&self, other: &Self) -> bool { + self.as_u256().partial_cmp(other.as_u256()) == Some(core::cmp::Ordering::Equal) + } +} + +impl Debug for Bn254Fr { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Bn254Fr({:?})", self.as_u256()) + } +} + +impl Bn254 { + pub(crate) fn new(env: &Env) -> Bn254 { + Bn254 { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + /// Adds two points `p0` and `p1` in G1. + pub fn g1_add(&self, p0: &Bn254G1Affine, p1: &Bn254G1Affine) -> Bn254G1Affine { + let env = self.env(); + let bin = + internal::Env::bn254_g1_add(env, p0.to_object(), p1.to_object()).unwrap_infallible(); + unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Multiplies a point `p0` in G1 by a scalar. + pub fn g1_mul(&self, p0: &Bn254G1Affine, scalar: &Bn254Fr) -> Bn254G1Affine { + let env = self.env(); + let bin = + internal::Env::bn254_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); + unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + // pairing + + /// Performs a multi-pairing check between vectors of points in G1 and G2. + /// + /// This function computes the pairing for each pair of points in the + /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if + /// the product of all pairings is equal to 1 in the target group Bn254Fp. + /// + /// # Returns: + /// - `true` if the pairing check holds (i.e., the product of pairings equals 1), + /// otherwise `false`. + /// + /// # Panics: + /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. + pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { + let env = self.env(); + internal::Env::bn254_multi_pairing_check(env, vp1.into(), vp2.into()) + .unwrap_infallible() + .into() + } + + /// Performs a multi-scalar multiplication (MSM) operation in G1. + pub fn g1_msm(&self, vp: Vec, vs: Vec) -> Bn254G1Affine { + let env = self.env(); + let bin = internal::Env::bn254_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); + unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } + } + + /// Checks if a G1 point is on the BN254 curve. + pub fn g1_is_on_curve(&self, point: &Bn254G1Affine) -> bool { + let env = self.env(); + internal::Env::bn254_g1_is_on_curve(env, point.to_object()) + .unwrap_infallible() + .into() + } + + // scalar arithmetic + + /// Adds two scalars in the BN254 scalar field `Bn254Fr`. + pub fn fr_add(&self, lhs: &Bn254Fr, rhs: &Bn254Fr) -> Bn254Fr { + let env = self.env(); + let v = internal::Env::bn254_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Subtracts one scalar from another in the BN254 scalar field `Bn254Fr`. + pub fn fr_sub(&self, lhs: &Bn254Fr, rhs: &Bn254Fr) -> Bn254Fr { + let env = self.env(); + let v = internal::Env::bn254_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Multiplies two scalars in the BN254 scalar field `Bn254Fr`. + pub fn fr_mul(&self, lhs: &Bn254Fr, rhs: &Bn254Fr) -> Bn254Fr { + let env = self.env(); + let v = internal::Env::bn254_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Raises a scalar to the power of a given exponent in the BN254 scalar field `Bn254Fr`. + pub fn fr_pow(&self, lhs: &Bn254Fr, rhs: u64) -> Bn254Fr { + let env = self.env(); + let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); + let v = internal::Env::bn254_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } + + /// Computes the multiplicative inverse of a scalar in the BN254 scalar field `Bn254Fr`. + pub fn fr_inv(&self, lhs: &Bn254Fr) -> Bn254Fr { + let env = self.env(); + let v = internal::Env::bn254_fr_inv(env, lhs.into()).unwrap_infallible(); + U256::try_from_val(env, &v).unwrap_infallible().into() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_g1affine_to_val() { + let env = Env::default(); + + let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64])); + let val: Val = g1.clone().into_val(&env); + let rt: Bn254G1Affine = val.into_val(&env); + + assert_eq!(g1, rt); + } + + #[test] + fn test_ref_g1affine_to_val() { + let env = Env::default(); + + let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64])); + let val: Val = (&g1).into_val(&env); + let rt: Bn254G1Affine = val.into_val(&env); + + assert_eq!(g1, rt); + } + + #[test] + fn test_double_ref_g1affine_to_val() { + let env = Env::default(); + + let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64])); + let val: Val = (&&g1).into_val(&env); + let rt: Bn254G1Affine = val.into_val(&env); + + assert_eq!(g1, rt); + } + + #[test] + fn test_fr_to_val() { + let env = Env::default(); + + let fr = Bn254Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); + let val: Val = fr.clone().into_val(&env); + let rt: Bn254Fr = val.into_val(&env); + + assert_eq!(fr, rt); + } + + #[test] + fn test_ref_fr_to_val() { + let env = Env::default(); + + let fr = Bn254Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); + let val: Val = (&fr).into_val(&env); + let rt: Bn254Fr = val.into_val(&env); + + assert_eq!(fr, rt); + } + + #[test] + fn test_double_ref_fr_to_val() { + let env = Env::default(); + + let fr = Bn254Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); + let val: Val = (&&fr).into_val(&env); + let rt: Bn254Fr = val.into_val(&env); + + assert_eq!(fr, rt); + } + + #[test] + fn test_fr_eq_both_unreduced() { + // Both inputs are user-provided unreduced values representing the same field element + let env = Env::default(); + let r = fr_modulus(&env); + let one = U256::from_u32(&env, 1); + + let a = Bn254Fr::from_u256(r.add(&one)); // r+1 ≡ 1 (mod r) + let b = Bn254Fr::from_u256(one.clone()); // 1 + assert_eq!(a, b); + + // Both unreduced by different multiples of r + let two_r_plus_one = r.add(&r).add(&one); + let c = Bn254Fr::from_u256(two_r_plus_one); // 2r+1 ≡ 1 (mod r) + assert_eq!(a, c); + assert_eq!(b, c); + } + + #[test] + fn test_fr_eq_unreduced_vs_zero() { + // value == r should reduce to 0 + let env = Env::default(); + let r = fr_modulus(&env); + let zero = U256::from_u32(&env, 0); + + let a = Bn254Fr::from_u256(r); + let b = Bn254Fr::from_u256(zero); + assert_eq!(a, b); + } + + #[test] + fn test_fr_reduced_value_unchanged() { + // value < r should be preserved as-is + let env = Env::default(); + let r = fr_modulus(&env); + let val = r.sub(&U256::from_u32(&env, 1)); // r-1 + + let fr = Bn254Fr::from_u256(val.clone()); + assert_eq!(fr.to_u256(), val); + + // small values + let fr42 = Bn254Fr::from_u256(U256::from_u32(&env, 42)); + assert_eq!(fr42.to_u256(), U256::from_u32(&env, 42)); + } + + #[test] + fn test_fr_from_bytes_reduces() { + // from_bytes should also reduce since it goes through From + let env = Env::default(); + let one_fr = Bn254Fr::from_u256(U256::from_u32(&env, 1)); + + // BN254 r+1 as big-endian bytes + let fr_from_bytes = Bn254Fr::from_bytes(bytesn!( + &env, + 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000002 + )); + assert_eq!(fr_from_bytes, one_fr); + } + + #[test] + fn test_fr_try_from_val_reduces() { + // TryFromVal path must also reduce + let env = Env::default(); + let r = fr_modulus(&env); + let one = U256::from_u32(&env, 1); + + // Create an unreduced U256 value (r+1), convert to Val, then to Fr + let unreduced_u256 = r.add(&one); + let val: Val = unreduced_u256.into_val(&env); + let fr_from_val: Bn254Fr = val.into_val(&env); + let fr_one = Bn254Fr::from_u256(one); + assert_eq!(fr_from_val, fr_one); + } + + #[test] + fn test_fr_u256_into_reduces() { + // Direct From::from / .into() path must reduce + let env = Env::default(); + let r = fr_modulus(&env); + let one = U256::from_u32(&env, 1); + + let fr: Bn254Fr = r.add(&one).into(); // r+1 via .into() + let fr_one: Bn254Fr = one.into(); + assert_eq!(fr, fr_one); + } + + // Bn254Fp validation tests + + #[test] + fn test_bn254_fp_max_valid_accepted() { + let env = Env::default(); + // p - 1 (last byte 0x46 instead of 0x47) + let mut p_minus_1 = BN254_FP_MODULUS_BE; + p_minus_1[BN254_FP_SERIALIZED_SIZE - 1] -= 1; + let _ = Bn254Fp::from_array(&env, &p_minus_1); + } + + #[test] + #[should_panic(expected = "Bn254: Invalid Fp")] + fn test_bn254_fp_at_modulus_panics() { + let env = Env::default(); + let _ = Bn254Fp::from_array(&env, &BN254_FP_MODULUS_BE); + } + + #[test] + #[should_panic(expected = "Bn254: Invalid Fp")] + fn test_bn254_fp_above_modulus_panics() { + let env = Env::default(); + let mut above = BN254_FP_MODULUS_BE; + above[BN254_FP_SERIALIZED_SIZE - 1] += 1; // p + 1 + let _ = Bn254Fp::from_array(&env, &above); + } + + #[test] + fn test_bn254_fp_from_bytes_validates() { + let env = Env::default(); + // Zero should be valid + let _ = Bn254Fp::from_bytes(BytesN::from_array(&env, &[0u8; BN254_FP_SERIALIZED_SIZE])); + } + + #[test] + #[should_panic(expected = "Bn254: Invalid Fp")] + fn test_bn254_fp_from_bytes_rejects_modulus() { + let env = Env::default(); + let _ = Bn254Fp::from_bytes(BytesN::from_array(&env, &BN254_FP_MODULUS_BE)); + } + + #[test] + #[should_panic(expected = "Bn254: Invalid Fp")] + fn test_bn254_fp_try_from_val_rejects_modulus() { + let env = Env::default(); + let bytes = BytesN::from_array(&env, &BN254_FP_MODULUS_BE); + let val: Val = bytes.into_val(&env); + let _: Bn254Fp = val.into_val(&env); + } + + #[test] + fn test_bn254_fp_modulus_matches_arkworks() { + use ark_bn254::Fq; + use ark_ff::{BigInteger, PrimeField}; + + let be_bytes = Fq::MODULUS.to_bytes_be(); + assert_eq!( + be_bytes.as_slice(), + &BN254_FP_MODULUS_BE, + "BN254 Fp modulus does not match arkworks" + ); + } + + #[test] + fn test_bn254_fr_modulus_matches_arkworks() { + use ark_bn254::Fr as ArkFr; + use ark_ff::{BigInteger, PrimeField}; + + let be_bytes = ArkFr::MODULUS.to_bytes_be(); + assert_eq!( + be_bytes.as_slice(), + &BN254_FR_MODULUS_BE, + "BN254 Fr modulus does not match arkworks" + ); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs new file mode 100644 index 0000000..fe19ee1 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs @@ -0,0 +1,64 @@ +use crate::BytesN; + +// This routine was copied with slight modification from the arkworks library: +// https://github.com/arkworks-rs/algebra/blob/bf1c9b22b30325ef4df4f701dedcb6dea904c587/ff/src/biginteger/arithmetic.rs#L66-L79 +// Copyright 2022 arkworks contributors. arkworks zkSNARK ecosystem [Computer software]. https://github.com/arkworks-rs/ +// Licensed under the Apache License, Version 2.0 +fn sbb_for_sub_with_borrow(a: &mut u64, b: u64, borrow: u8) -> u8 { + let tmp = (1u128 << 64) + u128::from(*a) - u128::from(b) - u128::from(borrow); + // casting is safe here because `tmp` can only exceed u64 by a single + // (borrow) bit, which we capture in the next line. + *a = tmp as u64; + u8::from(tmp >> 64 == 0) +} + +#[derive(Debug)] +pub(crate) struct BigInt(pub [u64; N]); + +impl BigInt { + pub fn sub_with_borrow(&mut self, other: &Self) -> bool { + let mut borrow = 0; + for i in 0..N { + borrow = sbb_for_sub_with_borrow(&mut self.0[i], other.0[i], borrow); + } + borrow != 0 + } + + pub fn copy_into_array(&self, slice: &mut [u8; M]) { + const { + if M != N * 8 { + panic!("BigInt::copy_into_array with mismatched array length") + } + } + + for i in 0..N { + let limb_bytes = self.0[N - 1 - i].to_be_bytes(); + slice[i * 8..(i + 1) * 8].copy_from_slice(&limb_bytes); + } + } + + pub fn is_zero(&self) -> bool { + self.0 == [0; N] + } +} + +impl From<&BytesN> for BigInt { + fn from(bytes: &BytesN) -> Self { + const { + if M != N * 8 { + panic!("BytesN::Into - length mismatch") + } + } + + let array = bytes.to_array(); + let mut limbs = [0u64; N]; + for i in 0..N { + let start = i * 8; + let end = start + 8; + let mut chunk = [0u8; 8]; + chunk.copy_from_slice(&array[start..end]); + limbs[N - 1 - i] = u64::from_be_bytes(chunk); + } + BigInt(limbs) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/deploy.rs b/temp_sdk/soroban-sdk-26.0.1/src/deploy.rs new file mode 100644 index 0000000..689e8e6 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/deploy.rs @@ -0,0 +1,469 @@ +//! Deploy contains types for deploying contracts. +//! +//! Contracts are assigned an ID that is derived from a set of arguments. A +//! contract may choose which set of arguments to use to deploy with: +//! +//! - [Deployer::with_current_contract] – A contract deployed by the currently +//! executing contract will have an ID derived from the currently executing +//! contract's ID. +//! +//! The deployer can be created using [Env::deployer]. +//! +//! ### Examples +//! +//! #### Deploy a contract without constructor (or 0-argument constructor) +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol}; +//! +//! const DEPLOYED_WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn deploy(env: Env, wasm_hash: BytesN<32>) { +//! let salt = [0u8; 32]; +//! let deployer = env.deployer().with_current_contract(salt); +//! let contract_address = deployer.deploy_v2(wasm_hash, ()); +//! // ... +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let contract_address = env.register(Contract, ()); +//! let contract = ContractClient::new(&env, &contract_address); +//! // Upload the contract code before deploying its instance. +//! let wasm_hash = env.deployer().upload_contract_wasm(DEPLOYED_WASM); +//! contract.deploy(&wasm_hash); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! #### Deploy a contract with a multi-argument constructor +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol, IntoVal}; +//! +//! const DEPLOYED_WASM_WITH_CTOR: &[u8] = include_bytes!("../doctest_fixtures/contract_with_constructor.wasm"); +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn deploy_with_constructor(env: Env, wasm_hash: BytesN<32>) { +//! let salt = [1u8; 32]; +//! let deployer = env.deployer().with_current_contract(salt); +//! let contract_address = deployer.deploy_v2( +//! wasm_hash, +//! (1_u32, 2_i64), +//! ); +//! // ... +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let contract_address = env.register(Contract, ()); +//! let contract = ContractClient::new(&env, &contract_address); +//! // Upload the contract code before deploying its instance. +//! let wasm_hash = env.deployer().upload_contract_wasm(DEPLOYED_WASM_WITH_CTOR); +//! contract.deploy_with_constructor(&wasm_hash); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! #### Derive before deployment what the address of a contract will be +//! +//! ``` +//! use soroban_sdk::{contract, contractimpl, Address, BytesN, Env, Symbol, IntoVal}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn deploy_contract_address(env: Env) -> Address { +//! let salt = [1u8; 32]; +//! let deployer = env.deployer().with_current_contract(salt); +//! // Deployed contract address is deterministic and can be accessed +//! // before deploying the contract. It is derived from the deployer +//! // (the current contract's address) and the salt passed in above. +//! deployer.deployed_address() +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let contract_address = env.register(Contract, ()); +//! let contract = ContractClient::new(&env, &contract_address); +//! assert_eq!( +//! contract.deploy_contract_address(), +//! Address::from_str(&env, "CBESJIMX7J53SWJGJ7WQ6QTLJI4S5LPPJNC2BNVD63GIKAYCDTDOO322"), +//! ); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` + +use crate::{ + env::internal::{ContractTtlExtension, Env as _}, + unwrap::UnwrapInfallible, + Address, Bytes, BytesN, ConstructorArgs, Env, IntoVal, +}; + +/// Deployer provides access to deploying contracts. +pub struct Deployer { + env: Env, +} + +impl Deployer { + pub(crate) fn new(env: &Env) -> Deployer { + Deployer { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + /// Get a deployer that deploys contract that derive the contract IDs + /// from the current contract and provided salt. + pub fn with_current_contract( + &self, + salt: impl IntoVal>, + ) -> DeployerWithAddress { + DeployerWithAddress { + env: self.env.clone(), + address: self.env.current_contract_address(), + salt: salt.into_val(&self.env), + } + } + + /// Get a deployer that deploys contracts that derive the contract ID + /// from the provided address and salt. + /// + /// The deployer address must authorize all the deployments. + pub fn with_address( + &self, + address: Address, + salt: impl IntoVal>, + ) -> DeployerWithAddress { + DeployerWithAddress { + env: self.env.clone(), + address, + salt: salt.into_val(&self.env), + } + } + + /// Get a deployer that deploys an instance of Stellar Asset Contract + /// corresponding to the provided serialized asset. + /// + /// `serialized_asset` is the Stellar `Asset` XDR serialized to bytes. Refer + /// to `[soroban_sdk::xdr::Asset]` + pub fn with_stellar_asset( + &self, + serialized_asset: impl IntoVal, + ) -> DeployerWithAsset { + DeployerWithAsset { + env: self.env.clone(), + serialized_asset: serialized_asset.into_val(&self.env), + } + } + + /// Upload the contract Wasm code to the network. + /// + /// Returns the hash of the uploaded Wasm that can be then used for + /// the contract deployment. + /// ### Examples + /// ``` + /// use soroban_sdk::{BytesN, Env}; + /// + /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// env.deployer().upload_contract_wasm(WASM); + /// } + /// ``` + pub fn upload_contract_wasm(&self, contract_wasm: impl IntoVal) -> BytesN<32> { + self.env + .upload_wasm(contract_wasm.into_val(&self.env).to_object()) + .unwrap_infallible() + .into_val(&self.env) + } + + /// Replaces the executable of the current contract with the provided Wasm. + /// + /// The Wasm blob identified by the `wasm_hash` has to be already present + /// in the ledger (uploaded via `[Deployer::upload_contract_wasm]`). + /// + /// The function won't do anything immediately. The contract executable + /// will only be updated after the invocation has successfully finished. + pub fn update_current_contract_wasm(&self, wasm_hash: impl IntoVal>) { + self.env + .update_current_contract_wasm(wasm_hash.into_val(&self.env).to_object()) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract instance and code. + /// + /// Extends the TTL of the instance and code only if the TTL for the provided contract is below `threshold` ledgers. + /// The TTL will then become `extend_to`. Note that the `threshold` check and TTL extensions are done for both the + /// contract code and contract instance, so it's possible that one is bumped but not the other depending on what the + /// current TTL's are. + /// + /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. + pub fn extend_ttl(&self, contract_address: Address, threshold: u32, extend_to: u32) { + self.env + .extend_contract_instance_and_code_ttl( + contract_address.to_object(), + threshold.into(), + extend_to.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract instance. + /// + /// Same as [`extend_ttl`](Self::extend_ttl) but only for contract instance. + pub fn extend_ttl_for_contract_instance( + &self, + contract_address: Address, + threshold: u32, + extend_to: u32, + ) { + self.env + .extend_contract_instance_ttl( + contract_address.to_object(), + threshold.into(), + extend_to.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract code. + /// + /// Same as [`extend_ttl`](Self::extend_ttl) but only for contract code. + pub fn extend_ttl_for_code(&self, contract_address: Address, threshold: u32, extend_to: u32) { + self.env + .extend_contract_code_ttl( + contract_address.to_object(), + threshold.into(), + extend_to.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract instance and code with limits on the extension. + /// + /// Extends the TTL of the instance and code to be up to `extend_to` ledgers. + /// The extension only happens if it exceeds `min_extension` ledgers, otherwise + /// this is a no-op. The amount of extension will not exceed `max_extension` ledgers. + /// + /// Note that the extension is applied to both the contract code and contract instance, + /// so it's possible that one is extended but not the other depending on their current TTLs. + /// + /// The TTL is the number of ledgers between the current ledger and the final ledger + /// the data can still be accessed. + pub fn extend_ttl_with_limits( + &self, + contract_address: Address, + extend_to: u32, + min_extension: u32, + max_extension: u32, + ) { + self.env + .extend_contract_instance_and_code_ttl_v2( + contract_address.to_object(), + ContractTtlExtension::InstanceAndCode, + extend_to.into(), + min_extension.into(), + max_extension.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract instance with limits on the extension. + /// + /// Same as [`extend_ttl_with_limits`](Self::extend_ttl_with_limits) but only for contract instance. + pub fn extend_ttl_for_contract_instance_with_limits( + &self, + contract_address: Address, + extend_to: u32, + min_extension: u32, + max_extension: u32, + ) { + self.env + .extend_contract_instance_and_code_ttl_v2( + contract_address.to_object(), + ContractTtlExtension::Instance, + extend_to.into(), + min_extension.into(), + max_extension.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract code with limits on the extension. + /// + /// Same as [`extend_ttl_with_limits`](Self::extend_ttl_with_limits) but only for contract code. + pub fn extend_ttl_for_code_with_limits( + &self, + contract_address: Address, + extend_to: u32, + min_extension: u32, + max_extension: u32, + ) { + self.env + .extend_contract_instance_and_code_ttl_v2( + contract_address.to_object(), + ContractTtlExtension::Code, + extend_to.into(), + min_extension.into(), + max_extension.into(), + ) + .unwrap_infallible(); + } +} + +/// A deployer that deploys a contract that has its ID derived from the provided +/// address and salt. +pub struct DeployerWithAddress { + env: Env, + address: Address, + salt: BytesN<32>, +} + +impl DeployerWithAddress { + /// Return the address of the contract defined by the deployer. + /// + /// This function can be called at anytime, before or after the contract is + /// deployed, because contract addresses are deterministic. + pub fn deployed_address(&self) -> Address { + self.env + .get_contract_id(self.address.to_object(), self.salt.to_object()) + .unwrap_infallible() + .into_val(&self.env) + } + + /// Deploy a contract that uses Wasm executable with provided hash. + /// + /// The address of the deployed contract is defined by the deployer address + /// and provided salt. + /// + /// Returns the deployed contract's address. + #[deprecated(note = "use deploy_v2")] + pub fn deploy(&self, wasm_hash: impl IntoVal>) -> Address { + let env = &self.env; + let address_obj = env + .create_contract( + self.address.to_object(), + wasm_hash.into_val(env).to_object(), + self.salt.to_object(), + ) + .unwrap_infallible(); + unsafe { Address::unchecked_new(env.clone(), address_obj) } + } + + /// Deploy a contract that uses Wasm executable with provided hash. + /// + /// The constructor args will be passed to the contract's constructor. Pass + /// `()` for contract's with no constructor or a constructor with zero + /// arguments. + /// + /// The address of the deployed contract is defined by the deployer address + /// and provided salt. + /// + /// Returns the deployed contract's address. + pub fn deploy_v2( + &self, + wasm_hash: impl IntoVal>, + constructor_args: A, + ) -> Address + where + A: ConstructorArgs, + { + let env = &self.env; + let address_obj = env + .create_contract_with_constructor( + self.address.to_object(), + wasm_hash.into_val(env).to_object(), + self.salt.to_object(), + constructor_args.into_val(env).to_object(), + ) + .unwrap_infallible(); + unsafe { Address::unchecked_new(env.clone(), address_obj) } + } +} + +pub struct DeployerWithAsset { + env: Env, + serialized_asset: Bytes, +} + +impl DeployerWithAsset { + /// Return the address of the contract defined by the deployer. + /// + /// This function can be called at anytime, before or after the contract is + /// deployed, because contract addresses are deterministic. + pub fn deployed_address(&self) -> Address { + self.env + .get_asset_contract_id(self.serialized_asset.to_object()) + .unwrap_infallible() + .into_val(&self.env) + } + + pub fn deploy(&self) -> Address { + self.env + .create_asset_contract(self.serialized_asset.to_object()) + .unwrap_infallible() + .into_val(&self.env) + } +} + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +mod testutils { + use crate::deploy::Deployer; + use crate::Address; + + impl crate::testutils::Deployer for Deployer { + fn get_contract_instance_ttl(&self, contract: &Address) -> u32 { + self.env + .host() + .get_contract_instance_live_until_ledger(contract.to_object()) + .unwrap() + .checked_sub(self.env.ledger().sequence()) + .unwrap() + } + + fn get_contract_code_ttl(&self, contract: &Address) -> u32 { + self.env + .host() + .get_contract_code_live_until_ledger(contract.to_object()) + .unwrap() + .checked_sub(self.env.ledger().sequence()) + .unwrap() + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/env.rs b/temp_sdk/soroban-sdk-26.0.1/src/env.rs new file mode 100644 index 0000000..216a42e --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/env.rs @@ -0,0 +1,2240 @@ +use core::convert::Infallible; + +#[cfg(target_family = "wasm")] +pub mod internal { + use core::convert::Infallible; + + pub use soroban_env_guest::*; + pub type EnvImpl = Guest; + pub type MaybeEnvImpl = Guest; + + // In the Guest case, Env::Error is already Infallible so there is no work + // to do to "reject an error": if an error occurs in the environment, the + // host will trap our VM and we'll never get here at all. + pub(crate) fn reject_err(_env: &Guest, r: Result) -> Result { + r + } +} + +#[cfg(not(target_family = "wasm"))] +pub mod internal { + use core::convert::Infallible; + + pub use soroban_env_host::*; + pub type EnvImpl = Host; + pub type MaybeEnvImpl = Option; + + // When we have `feature="testutils"` (or are in cfg(test)) we enable feature + // `soroban-env-{common,host}/testutils` which in turn adds the helper method + // `Env::escalate_error_to_panic` to the Env trait. + // + // When this is available we want to use it, because it works in concert + // with a _different_ part of the host that's also `testutils`-gated: the + // mechanism for emulating the WASM VM error-handling semantics with native + // contracts. In particular when a WASM contract calls a host function that + // fails with some error E, the host traps the VM (not returning to it at + // all) and propagates E to the caller of the contract. This is simulated in + // the native case by returning a (nontrivial) error E to us here, which we + // then "reject" back to the host, which stores E in a temporary cell inside + // any `TestContract` frame in progress and then _panics_, unwinding back to + // a panic-catcher it installed when invoking the `TestContract` frame, and + // then extracting E from the frame and returning it to its caller. This + // simulates the "crash, but catching the error" behavior of the WASM case. + // This only works if we panic via `escalate_error_to_panic`. + // + // (The reason we don't just panic_any() here and let the panic-catcher do a + // type-based catch is that there might _be_ no panic-catcher around us, and + // we want to print out a nice error message in that case too, which + // panic_any() does not do us the favor of producing. This is all very + // subtle. See also soroban_env_host::Host::escalate_error_to_panic.) + #[cfg(any(test, feature = "testutils"))] + pub(crate) fn reject_err(env: &Host, r: Result) -> Result { + r.map_err(|e| env.escalate_error_to_panic(e)) + } + + // When we're _not_ in a cfg enabling `soroban-env-{common,host}/testutils`, + // there is no `Env::escalate_error_to_panic` to call, so we just panic + // here. But this is ok because in that case there is also no multi-contract + // calling machinery set up, nor probably any panic-catcher installed that + // we need to hide error values for the benefit of. Any panic in this case + // is probably going to unwind completely anyways. No special case needed. + #[cfg(not(any(test, feature = "testutils")))] + pub(crate) fn reject_err(_env: &Host, r: Result) -> Result { + r.map_err(|e| panic!("{:?}", e)) + } + + #[doc(hidden)] + impl Convert for super::Env + where + EnvImpl: Convert, + { + type Error = >::Error; + fn convert(&self, f: F) -> Result { + self.env_impl.convert(f) + } + } +} + +pub use internal::xdr; +pub use internal::ContractTtlExtension; +pub use internal::ConversionError; +pub use internal::EnvBase; +pub use internal::Error; +pub use internal::MapObject; +pub use internal::SymbolStr; +pub use internal::TryFromVal; +pub use internal::TryIntoVal; +pub use internal::Val; +pub use internal::VecObject; + +pub trait IntoVal { + fn into_val(&self, e: &E) -> T; +} + +pub trait FromVal { + fn from_val(e: &E, v: &T) -> Self; +} + +impl FromVal for U +where + U: TryFromVal, +{ + fn from_val(e: &E, v: &T) -> Self { + U::try_from_val(e, v).unwrap_optimized() + } +} + +impl IntoVal for U +where + T: FromVal, +{ + fn into_val(&self, e: &E) -> T { + T::from_val(e, self) + } +} + +use crate::auth::InvokerContractAuthEntry; +use crate::unwrap::UnwrapInfallible; +use crate::unwrap::UnwrapOptimized; +use crate::InvokeError; +use crate::{ + crypto::Crypto, deploy::Deployer, events::Events, ledger::Ledger, logs::Logs, prng::Prng, + storage::Storage, Address, Vec, +}; +use internal::{ + AddressObject, Bool, BytesObject, DurationObject, I128Object, I256Object, I256Val, I64Object, + MuxedAddressObject, StorageType, StringObject, Symbol, SymbolObject, TimepointObject, + U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Void, +}; + +#[doc(hidden)] +#[derive(Clone)] +pub struct MaybeEnv { + maybe_env_impl: internal::MaybeEnvImpl, + #[cfg(any(test, feature = "testutils"))] + test_state: Option, +} + +#[cfg(target_family = "wasm")] +impl TryFrom for Env { + type Error = Infallible; + + fn try_from(_value: MaybeEnv) -> Result { + Ok(Env { + env_impl: internal::EnvImpl {}, + }) + } +} + +impl Default for MaybeEnv { + fn default() -> Self { + Self::none() + } +} + +#[cfg(target_family = "wasm")] +impl MaybeEnv { + // separate function to be const + pub const fn none() -> Self { + Self { + maybe_env_impl: internal::EnvImpl {}, + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl MaybeEnv { + // separate function to be const + pub const fn none() -> Self { + Self { + maybe_env_impl: None, + #[cfg(any(test, feature = "testutils"))] + test_state: None, + } + } +} + +#[cfg(target_family = "wasm")] +impl From for MaybeEnv { + fn from(value: Env) -> Self { + MaybeEnv { + maybe_env_impl: value.env_impl, + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFrom for Env { + type Error = ConversionError; + + fn try_from(value: MaybeEnv) -> Result { + if let Some(env_impl) = value.maybe_env_impl { + Ok(Env { + env_impl, + #[cfg(any(test, feature = "testutils"))] + test_state: value.test_state.unwrap_or_default(), + }) + } else { + Err(ConversionError) + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for MaybeEnv { + fn from(value: Env) -> Self { + MaybeEnv { + maybe_env_impl: Some(value.env_impl.clone()), + #[cfg(any(test, feature = "testutils"))] + test_state: Some(value.test_state.clone()), + } + } +} + +/// The [Env] type provides access to the environment the contract is executing +/// within. +/// +/// The [Env] provides access to information about the currently executing +/// contract, who invoked it, contract data, functions for signing, hashing, +/// etc. +/// +/// Most types require access to an [Env] to be constructed or converted. +#[derive(Clone)] +pub struct Env { + env_impl: internal::EnvImpl, + #[cfg(any(test, feature = "testutils"))] + test_state: EnvTestState, +} + +impl Default for Env { + #[cfg(not(any(test, feature = "testutils")))] + fn default() -> Self { + Self { + env_impl: Default::default(), + } + } + + #[cfg(any(test, feature = "testutils"))] + fn default() -> Self { + Self::new_with_config(EnvTestConfig::default()) + } +} + +#[cfg(any(test, feature = "testutils"))] +#[derive(Default, Clone)] +struct LastEnv { + test_name: String, + number: usize, +} + +#[cfg(any(test, feature = "testutils"))] +thread_local! { + static LAST_ENV: RefCell> = RefCell::new(None); +} + +#[cfg(any(test, feature = "testutils"))] +#[derive(Clone, Default)] +struct EnvTestState { + test_name: Option, + number: usize, + config: EnvTestConfig, + generators: Rc>, + auth_snapshot: Rc>, + snapshot: Option>, +} + +/// Config for changing the default behavior of the Env when used in tests. +#[cfg(any(test, feature = "testutils"))] +#[derive(Clone)] +pub struct EnvTestConfig { + /// Capture a test snapshot when the Env is dropped, causing a test snapshot + /// JSON file to be written to disk when the Env is no longer referenced. + /// Defaults to true. + pub capture_snapshot_at_drop: bool, + // NOTE: Next time a field needs to be added to EnvTestConfig it will be a breaking change, + // take the opportunity to make the current field private, new fields private, and settable via + // functions. Why: So that it is the last time a breaking change is needed to the type. +} + +#[cfg(any(test, feature = "testutils"))] +impl Default for EnvTestConfig { + fn default() -> Self { + Self { + capture_snapshot_at_drop: true, + } + } +} + +impl Env { + /// Panic with the given error. + /// + /// Equivalent to `panic!`, but with an error value instead of a string. + #[doc(hidden)] + #[cfg(feature = "experimental_spec_shaking_v2")] + #[inline(always)] + pub fn panic_with_error(&self, error: I) -> ! + where + I: Into + crate::SpecShakingMarker, + { + I::spec_shaking_marker(); + self.panic_with_error_inner(error.into()) + } + + /// Panic with the given error. + /// + /// Equivalent to `panic!`, but with an error value instead of a string. + #[doc(hidden)] + #[cfg(not(feature = "experimental_spec_shaking_v2"))] + #[inline(always)] + pub fn panic_with_error(&self, error: impl Into) -> ! { + self.panic_with_error_inner(error.into()) + } + + #[inline(always)] + fn panic_with_error_inner(&self, error: internal::Error) -> ! { + _ = internal::Env::fail_with_error(self, error); + #[cfg(target_family = "wasm")] + core::arch::wasm32::unreachable(); + #[cfg(not(target_family = "wasm"))] + unreachable!(); + } + + /// Get a [Storage] for accessing and updating persistent data owned by the + /// currently executing contract. + #[inline(always)] + pub fn storage(&self) -> Storage { + Storage::new(self) + } + + /// Get [Events] for publishing events associated with the + /// currently executing contract. + #[inline(always)] + pub fn events(&self) -> Events { + Events::new(self) + } + + /// Get a [Ledger] for accessing the current ledger. + #[inline(always)] + pub fn ledger(&self) -> Ledger { + Ledger::new(self) + } + + /// Get a deployer for deploying contracts. + #[inline(always)] + pub fn deployer(&self) -> Deployer { + Deployer::new(self) + } + + /// Get a [Crypto] for accessing the current cryptographic functions. + #[inline(always)] + pub fn crypto(&self) -> Crypto { + Crypto::new(self) + } + + /// # ⚠️ Hazardous Materials + /// + /// Get a [CryptoHazmat][crate::crypto::CryptoHazmat] for accessing the + /// cryptographic functions that are not generally recommended. Using them + /// incorrectly can introduce security vulnerabilities. Use [Crypto] if + /// possible. + #[cfg_attr(any(test, feature = "hazmat-crypto"), visibility::make(pub))] + #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-crypto")))] + #[inline(always)] + pub(crate) fn crypto_hazmat(&self) -> crate::crypto::CryptoHazmat { + crate::crypto::CryptoHazmat::new(self) + } + + /// Get a [Prng] for accessing the current functions which provide pseudo-randomness. + /// + /// # Warning + /// + /// **The pseudo-random generator returned is not suitable for + /// security-sensitive work.** + #[inline(always)] + pub fn prng(&self) -> Prng { + Prng::new(self) + } + + /// Get the Address object corresponding to the current executing contract. + pub fn current_contract_address(&self) -> Address { + let address = internal::Env::get_current_contract_address(self).unwrap_infallible(); + unsafe { Address::unchecked_new(self.clone(), address) } + } + + #[doc(hidden)] + pub(crate) fn require_auth_for_args(&self, address: &Address, args: Vec) { + internal::Env::require_auth_for_args(self, address.to_object(), args.to_object()) + .unwrap_infallible(); + } + + #[doc(hidden)] + pub(crate) fn require_auth(&self, address: &Address) { + internal::Env::require_auth(self, address.to_object()).unwrap_infallible(); + } + + /// Invokes a function of a contract that is registered in the [Env]. + /// + /// # Panics + /// + /// Will panic if the `contract_id` does not match a registered contract, + /// `func` does not match a function of the referenced contract, or the + /// number of `args` do not match the argument count of the referenced + /// contract function. + /// + /// Will panic if the contract that is invoked fails or aborts in anyway. + /// + /// Will panic if the value returned from the contract cannot be converted + /// into the type `T`. + pub fn invoke_contract( + &self, + contract_address: &Address, + func: &crate::Symbol, + args: Vec, + ) -> T + where + T: TryFromVal, + { + let rv = internal::Env::call( + self, + contract_address.to_object(), + func.to_symbol_val(), + args.to_object(), + ) + .unwrap_infallible(); + T::try_from_val(self, &rv) + .map_err(|_| ConversionError) + .unwrap() + } + + /// Invokes a function of a contract that is registered in the [Env], + /// returns an error if the invocation fails for any reason. + pub fn try_invoke_contract( + &self, + contract_address: &Address, + func: &crate::Symbol, + args: Vec, + ) -> Result, Result> + where + T: TryFromVal, + E: TryFrom, + E::Error: Into, + { + let rv = internal::Env::try_call( + self, + contract_address.to_object(), + func.to_symbol_val(), + args.to_object(), + ) + .unwrap_infallible(); + match internal::Error::try_from_val(self, &rv) { + Ok(err) => Err(E::try_from(err).map_err(Into::into)), + Err(ConversionError) => Ok(T::try_from_val(self, &rv)), + } + } + + /// Authorizes sub-contract calls on behalf of the current contract. + /// + /// All the direct calls that the current contract performs are always + /// considered to have been authorized. This is only needed to authorize + /// deeper calls that originate from the next contract call from the current + /// contract. + /// + /// For example, if the contract A calls contract B, contract + /// B calls contract C and contract C calls `A.require_auth()`, then an + /// entry corresponding to C call has to be passed in `auth_entries`. It + /// doesn't matter if contract B called `require_auth` or not. If contract A + /// calls contract B again, then `authorize_as_current_contract` has to be + /// called again with the respective entries. + /// + /// When testing a contract call that uses `authorize_as_current_contract`, avoid + /// using [`mock_all_auths_allowing_non_root_auth`][Self::mock_all_auths_allowing_non_root_auth]. + /// A test that uses this mock will not fail if a missing or incorrect + /// `authorize_as_current_contract` call is present. It is recommended to use other + /// authorization mocking functions like [`mock_auths`][Self::mock_auths] + /// or [`set_auths`][Self::set_auths] if needed. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{ + /// auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, + /// contract, contractimpl, vec, Address, Env, IntoVal, Symbol, + /// }; + /// + /// // Contract C performs authorization for addr + /// #[contract] + /// pub struct ContractC; + /// + /// #[contractimpl] + /// impl ContractC { + /// pub fn do_auth(_env: Env, addr: Address, amount: i128) -> i128 { + /// addr.require_auth(); + /// amount + /// } + /// } + /// + /// // Contract B performs authorization for `addr` and invokes Contract C with + /// // `addr` and `amount` as arguments. + /// #[contract] + /// pub struct ContractB; + /// + /// #[contractimpl] + /// impl ContractB { + /// pub fn call_c(env: Env, addr: Address, contract_c: Address, amount: i128) -> i128 { + /// addr.require_auth(); + /// ContractCClient::new(&env, &contract_c).do_auth(&addr, &amount) + /// } + /// } + /// + /// // Contract A authorizes Contract B to call Contract C on its behalf with `addr` and + /// // `amount` as arguments. + /// #[contract] + /// pub struct ContractA; + /// + /// #[contractimpl] + /// impl ContractA { + /// pub fn call_b(env: Env, contract_b: Address, contract_c: Address, amount: i128) -> i128 { + /// let curr_contract = env.current_contract_address(); + /// // Authorize the sub-call Contract B makes to Contract C + /// env.authorize_as_current_contract(vec![ + /// &env, + /// InvokerContractAuthEntry::Contract(SubContractInvocation { + /// context: ContractContext { + /// contract: contract_c.clone(), + /// fn_name: Symbol::new(&env, "do_auth"), + /// args: vec![&env, curr_contract.into_val(&env), amount.into_val(&env)], + /// }, + /// sub_invocations: vec![&env], + /// }), + /// ]); + /// ContractBClient::new(&env, &contract_b).call_c(&curr_contract, &contract_c, &amount) + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_a = env.register(ContractA, ()); + /// let contract_b = env.register(ContractB, ()); + /// let contract_c = env.register(ContractC, ()); + /// + /// // Auths are not mocked to ensure `authorize_as_current_contract` + /// // is working as intended. If Contract A includes additional auths, consider + /// // using `mock_auths` or `set_auths` for those authorizations. + /// + /// let client = ContractAClient::new(&env, &contract_a); + /// let result = client.call_b(&contract_b, &contract_c, &100); + /// assert_eq!(result, 100); + /// } + /// ``` + pub fn authorize_as_current_contract(&self, auth_entries: Vec) { + internal::Env::authorize_as_curr_contract(self, auth_entries.to_object()) + .unwrap_infallible(); + } + + /// Get the [Logs] for logging debug events. + #[inline(always)] + #[deprecated(note = "use [Env::logs]")] + #[doc(hidden)] + pub fn logger(&self) -> Logs { + self.logs() + } + + /// Get the [Logs] for logging debug events. + #[inline(always)] + pub fn logs(&self) -> Logs { + Logs::new(self) + } +} + +#[doc(hidden)] +#[cfg(not(target_family = "wasm"))] +impl Env { + pub(crate) fn is_same_env(&self, other: &Self) -> bool { + self.env_impl.is_same(&other.env_impl) + } +} + +#[cfg(any(test, feature = "testutils"))] +use crate::testutils::cost_estimate::CostEstimate; +#[cfg(any(test, feature = "testutils"))] +use crate::{ + auth, + testutils::{ + budget::Budget, cost_estimate::NetworkInvocationResourceLimits, default_ledger_info, + Address as _, AuthSnapshot, AuthorizedInvocation, ContractFunctionSet, EventsSnapshot, + Generators, Ledger as _, MockAuth, MockAuthContract, Register, Snapshot, + SnapshotSourceInput, StellarAssetContract, StellarAssetIssuer, + }, + Bytes, BytesN, ConstructorArgs, +}; +#[cfg(any(test, feature = "testutils"))] +use core::{cell::RefCell, cell::RefMut}; +#[cfg(any(test, feature = "testutils"))] +use internal::{InvocationEvent, InvocationResourceLimits}; +#[cfg(any(test, feature = "testutils"))] +use soroban_ledger_snapshot::LedgerSnapshot; +#[cfg(any(test, feature = "testutils"))] +use std::{path::Path, rc::Rc}; +#[cfg(any(test, feature = "testutils"))] +use xdr::{LedgerEntry, LedgerKey, LedgerKeyContractData, SorobanAuthorizationEntry}; + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl Env { + #[doc(hidden)] + pub fn in_contract(&self) -> bool { + self.env_impl.has_frame().unwrap() + } + + #[doc(hidden)] + pub fn host(&self) -> &internal::Host { + &self.env_impl + } + + #[doc(hidden)] + pub(crate) fn with_generator(&self, f: impl FnOnce(RefMut<'_, Generators>) -> T) -> T { + f((*self.test_state.generators).borrow_mut()) + } + + /// Create an Env with the test config. + pub fn new_with_config(config: EnvTestConfig) -> Env { + struct EmptySnapshotSource(); + + impl internal::storage::SnapshotSource for EmptySnapshotSource { + fn get( + &self, + _key: &Rc, + ) -> Result, Option)>, soroban_env_host::HostError> + { + Ok(None) + } + } + + let rf = Rc::new(EmptySnapshotSource()); + + Env::new_for_testutils(config, rf, None, None, None) + } + + /// Change the test config of an Env. + pub fn set_config(&mut self, config: EnvTestConfig) { + self.test_state.config = config; + } + + /// Used by multiple constructors to configure test environments consistently. + fn new_for_testutils( + config: EnvTestConfig, + recording_footprint: Rc, + generators: Option>>, + ledger_info: Option, + snapshot: Option>, + ) -> Env { + // Store in the Env the name of the test it is for, and a number so that within a test + // where one or more Env's have been created they can be uniquely identified relative to + // each other. + + let test_name = match std::thread::current().name() { + // When doc tests are running they're all run with the thread name main. There's no way + // to detect which doc test is being run. + Some(name) if name != "main" => Some(name.to_owned()), + _ => None, + }; + let number = if let Some(ref test_name) = test_name { + LAST_ENV.with_borrow_mut(|l| { + if let Some(last_env) = l.as_mut() { + if test_name != &last_env.test_name { + last_env.test_name = test_name.clone(); + last_env.number = 1; + 1 + } else { + let next_number = last_env.number + 1; + last_env.number = next_number; + next_number + } + } else { + *l = Some(LastEnv { + test_name: test_name.clone(), + number: 1, + }); + 1 + } + }) + } else { + 1 + }; + + let storage = internal::storage::Storage::with_recording_footprint(recording_footprint); + let budget = internal::budget::Budget::default(); + let env_impl = internal::EnvImpl::with_storage_and_budget(storage, budget.clone()); + env_impl + .set_source_account(xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519( + xdr::Uint256([0; 32]), + ))) + .unwrap(); + env_impl + .set_diagnostic_level(internal::DiagnosticLevel::Debug) + .unwrap(); + env_impl.set_base_prng_seed([0; 32]).unwrap(); + + let auth_snapshot = Rc::new(RefCell::new(AuthSnapshot::default())); + let auth_snapshot_in_hook = auth_snapshot.clone(); + env_impl + .set_invocation_hook(Some(Rc::new(move |host, event| { + match event { + InvocationEvent::Start => {} + InvocationEvent::Finish => { + let new_auths = host + .get_authenticated_authorizations() + // If an error occurs getting the authenticated authorizations + // it means that no auth has occurred. + .unwrap(); + (*auth_snapshot_in_hook).borrow_mut().0.push(new_auths); + } + } + }))) + .unwrap(); + env_impl.enable_invocation_metering(); + env_impl + .set_invocation_resource_limits(Some(InvocationResourceLimits::mainnet())) + .unwrap(); + + let env = Env { + env_impl, + test_state: EnvTestState { + test_name, + number, + config, + generators: generators.unwrap_or_default(), + snapshot, + auth_snapshot, + }, + }; + + let ledger_info = ledger_info.unwrap_or_else(default_ledger_info); + env.ledger().set(ledger_info); + + env + } + + /// Returns the resources metered during the last top level contract + /// invocation. + /// + /// In order to get non-`None` results, `enable_invocation_metering` has to + /// be called and at least one invocation has to happen after that. + /// + /// Take the return value with a grain of salt. The returned resources mostly + /// correspond only to the operations that have happened during the host + /// invocation, i.e. this won't try to simulate the work that happens in + /// production scenarios (e.g. certain XDR roundtrips). This also doesn't try + /// to model resources related to the transaction size. + /// + /// The returned value is as useful as the preceding setup, e.g. if a test + /// contract is used instead of a Wasm contract, all the costs related to + /// VM instantiation and execution, as well as Wasm reads/rent bumps will be + /// missed. + /// + /// While the resource metering may be useful for contract optimization, + /// keep in mind that resource and fee estimation may be imprecise. Use + /// simulation with RPC in order to get the exact resources for submitting + /// the transactions to the network. + pub fn cost_estimate(&self) -> CostEstimate { + CostEstimate::new(self.clone()) + } + + /// Register a contract with the [Env] for testing. + /// + /// Pass the contract type when the contract is defined in the current crate + /// and is being registered natively. Pass the contract wasm bytes when the + /// contract has been loaded as wasm. + /// + /// Pass the arguments for the contract's constructor, or `()` if none. For + /// contracts with a constructor, use the contract's generated `Args` type + /// to construct the arguments with the appropriate types for invoking + /// the constructor during registration. + /// + /// Returns the address of the registered contract that is the same as the + /// contract id passed in. + /// + /// If you need to specify the address the contract should be registered at, + /// use [`Env::register_at`]. + /// + /// ### Examples + /// Register a contract defined in the current crate, by specifying the type + /// name: + /// ``` + /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol}; + /// + /// #[contract] + /// pub struct Contract; + /// + /// #[contractimpl] + /// impl Contract { + /// pub fn __constructor(_env: Env, _input: u32) { + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(Contract, ContractArgs::__constructor(&123,)); + /// } + /// ``` + /// Register a contract wasm, by specifying the wasm bytes: + /// ``` + /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; + /// + /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(WASM, ()); + /// } + /// ``` + pub fn register<'a, C, A>(&self, contract: C, constructor_args: A) -> Address + where + C: Register, + A: ConstructorArgs, + { + contract.register(self, None, constructor_args) + } + + /// Register a contract with the [Env] for testing. + /// + /// Passing a contract ID for the first arguments registers the contract + /// with that contract ID. + /// + /// Registering a contract that is already registered replaces it. + /// Use re-registration with caution as it does not exist in the real + /// (on-chain) environment. Specifically, the new contract's constructor + /// will be called again during re-registration. That behavior only exists + /// for this test utility and is not reproducible on-chain, where contract + /// Wasm updates don't cause constructor to be called. + /// + /// Pass the contract type when the contract is defined in the current crate + /// and is being registered natively. Pass the contract wasm bytes when the + /// contract has been loaded as wasm. + /// + /// Returns the address of the registered contract that is the same as the + /// contract id passed in. + /// + /// ### Examples + /// Register a contract defined in the current crate, by specifying the type + /// name: + /// ``` + /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol}; + /// + /// #[contract] + /// pub struct Contract; + /// + /// #[contractimpl] + /// impl Contract { + /// pub fn __constructor(_env: Env, _input: u32) { + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = Address::generate(&env); + /// env.register_at(&contract_id, Contract, (123_u32,)); + /// } + /// ``` + /// Register a contract wasm, by specifying the wasm bytes: + /// ``` + /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; + /// + /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = Address::generate(&env); + /// env.register_at(&contract_id, WASM, ()); + /// } + /// ``` + pub fn register_at( + &self, + contract_id: &Address, + contract: C, + constructor_args: A, + ) -> Address + where + C: Register, + A: ConstructorArgs, + { + contract.register(self, contract_id, constructor_args) + } + + /// Register a contract with the [Env] for testing. + /// + /// Passing a contract ID for the first arguments registers the contract + /// with that contract ID. Providing `None` causes the Env to generate a new + /// contract ID that is assigned to the contract. + /// + /// If a contract has a constructor defined, then it will be called with + /// no arguments. If a constructor takes arguments, use `register`. + /// + /// Registering a contract that is already registered replaces it. + /// Use re-registration with caution as it does not exist in the real + /// (on-chain) environment. Specifically, the new contract's constructor + /// will be called again during re-registration. That behavior only exists + /// for this test utility and is not reproducible on-chain, where contract + /// Wasm updates don't cause constructor to be called. + /// + /// Returns the address of the registered contract. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol}; + /// + /// #[contract] + /// pub struct HelloContract; + /// + /// #[contractimpl] + /// impl HelloContract { + /// pub fn hello(env: Env, recipient: Symbol) -> Symbol { + /// todo!() + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register_contract(None, HelloContract); + /// } + /// ``` + #[deprecated(note = "use `register`")] + pub fn register_contract<'a, T: ContractFunctionSet + 'static>( + &self, + contract_id: impl Into>, + contract: T, + ) -> Address { + self.register_contract_with_constructor(contract_id, contract, ()) + } + + /// Register a contract with the [Env] for testing. + /// + /// This acts the in the same fashion as `register_contract`, but allows + /// passing arguments to the contract's constructor. + /// + /// Passing a contract ID for the first arguments registers the contract + /// with that contract ID. Providing `None` causes the Env to generate a new + /// contract ID that is assigned to the contract. + /// + /// Registering a contract that is already registered replaces it. + /// Use re-registration with caution as it does not exist in the real + /// (on-chain) environment. Specifically, the new contract's constructor + /// will be called again during re-registration. That behavior only exists + /// for this test utility and is not reproducible on-chain, where contract + /// Wasm updates don't cause constructor to be called. + /// + /// Returns the address of the registered contract. + pub(crate) fn register_contract_with_constructor< + 'a, + T: ContractFunctionSet + 'static, + A: ConstructorArgs, + >( + &self, + contract_id: impl Into>, + contract: T, + constructor_args: A, + ) -> Address { + struct InternalContractFunctionSet(pub(crate) T); + impl internal::ContractFunctionSet for InternalContractFunctionSet { + fn call( + &self, + func: &Symbol, + env_impl: &internal::EnvImpl, + args: &[Val], + ) -> Option { + let env = Env { + env_impl: env_impl.clone(), + test_state: Default::default(), + }; + self.0.call( + crate::Symbol::try_from_val(&env, func) + .unwrap_infallible() + .to_string() + .as_str(), + env, + args, + ) + } + } + + let contract_id = if let Some(contract_id) = contract_id.into() { + contract_id.clone() + } else { + Address::generate(self) + }; + self.env_impl + .register_test_contract_with_constructor( + contract_id.to_object(), + Rc::new(InternalContractFunctionSet(contract)), + constructor_args.into_val(self).to_object(), + ) + .unwrap(); + contract_id + } + + /// Register a contract in a Wasm file with the [Env] for testing. + /// + /// Passing a contract ID for the first arguments registers the contract + /// with that contract ID. Providing `None` causes the Env to generate a new + /// contract ID that is assigned to the contract. + /// + /// Registering a contract that is already registered replaces it. + /// Use re-registration with caution as it does not exist in the real + /// (on-chain) environment. Specifically, the new contract's constructor + /// will be called again during re-registration. That behavior only exists + /// for this test utility and is not reproducible on-chain, where contract + /// Wasm updates don't cause constructor to be called. + /// + /// Returns the address of the registered contract. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{BytesN, Env}; + /// + /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// env.register_contract_wasm(None, WASM); + /// } + /// ``` + #[deprecated(note = "use `register`")] + pub fn register_contract_wasm<'a>( + &self, + contract_id: impl Into>, + contract_wasm: impl IntoVal, + ) -> Address { + let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm); + self.register_contract_with_optional_contract_id_and_executable( + contract_id, + xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())), + crate::vec![&self], + ) + } + + /// Register a contract in a Wasm file with the [Env] for testing. + /// + /// This acts the in the same fashion as `register_contract`, but allows + /// passing arguments to the contract's constructor. + /// + /// Passing a contract ID for the first arguments registers the contract + /// with that contract ID. Providing `None` causes the Env to generate a new + /// contract ID that is assigned to the contract. + /// + /// Registering a contract that is already registered replaces it. + /// Use re-registration with caution as it does not exist in the real + /// (on-chain) environment. Specifically, the new contract's constructor + /// will be called again during re-registration. That behavior only exists + /// for this test utility and is not reproducible on-chain, where contract + /// Wasm updates don't cause constructor to be called. + /// + /// Returns the address of the registered contract. + pub(crate) fn register_contract_wasm_with_constructor<'a>( + &self, + contract_id: impl Into>, + contract_wasm: impl IntoVal, + constructor_args: impl ConstructorArgs, + ) -> Address { + let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm); + self.register_contract_with_optional_contract_id_and_executable( + contract_id, + xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())), + constructor_args.into_val(self), + ) + } + + /// Register the built-in Stellar Asset Contract with provided admin address. + /// + /// Returns a utility struct that contains the contract ID of the registered + /// token contract, as well as methods to read and update issuer flags. + /// + /// The contract will wrap a randomly-generated Stellar asset. This function + /// is useful for using in the tests when an arbitrary token contract + /// instance is needed. + pub fn register_stellar_asset_contract_v2(&self, admin: Address) -> StellarAssetContract { + let issuer_pk = self.with_generator(|mut g| g.address()); + let issuer_id = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256( + issuer_pk.clone(), + ))); + + let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount { + account_id: issuer_id.clone(), + })); + + if self.host().get_ledger_entry(&k).unwrap().is_none() { + let v = Rc::new(xdr::LedgerEntry { + data: xdr::LedgerEntryData::Account(xdr::AccountEntry { + account_id: issuer_id.clone(), + balance: 0, + flags: 0, + home_domain: Default::default(), + inflation_dest: None, + num_sub_entries: 0, + seq_num: xdr::SequenceNumber(0), + thresholds: xdr::Thresholds([1; 4]), + signers: xdr::VecM::default(), + ext: xdr::AccountEntryExt::V0, + }), + last_modified_ledger_seq: 0, + ext: xdr::LedgerEntryExt::V0, + }); + self.host().add_ledger_entry(&k, &v, None).unwrap(); + } + + let asset = xdr::Asset::CreditAlphanum4(xdr::AlphaNum4 { + asset_code: xdr::AssetCode4([b'a', b'a', b'a', 0]), + issuer: issuer_id.clone(), + }); + let create = xdr::HostFunction::CreateContract(xdr::CreateContractArgs { + contract_id_preimage: xdr::ContractIdPreimage::Asset(asset.clone()), + executable: xdr::ContractExecutable::StellarAsset, + }); + + let token_id: Address = self + .env_impl + .invoke_function(create) + .unwrap() + .try_into_val(self) + .unwrap(); + + let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap(); + self.env_impl + .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager) + .unwrap(); + let admin_result = self.try_invoke_contract::<(), Error>( + &token_id, + &soroban_sdk_macros::internal_symbol_short!("set_admin"), + (admin,).try_into_val(self).unwrap(), + ); + self.env_impl.set_auth_manager(prev_auth_manager).unwrap(); + admin_result.unwrap().unwrap(); + + let issuer = StellarAssetIssuer::new(self.clone(), issuer_id); + StellarAssetContract::new(token_id, issuer, asset) + } + + /// Register the built-in Stellar Asset Contract with provided admin address. + /// + /// Returns the contract ID of the registered token contract. + /// + /// The contract will wrap a randomly-generated Stellar asset. This function + /// is useful for using in the tests when an arbitrary token contract + /// instance is needed. + #[deprecated(note = "use [Env::register_stellar_asset_contract_v2]")] + pub fn register_stellar_asset_contract(&self, admin: Address) -> Address { + self.register_stellar_asset_contract_v2(admin).address() + } + + fn register_contract_with_optional_contract_id_and_executable<'a>( + &self, + contract_id: impl Into>, + executable: xdr::ContractExecutable, + constructor_args: Vec, + ) -> Address { + if let Some(contract_id) = contract_id.into() { + self.register_contract_with_contract_id_and_executable( + contract_id, + executable, + constructor_args, + ); + contract_id.clone() + } else { + self.register_contract_with_source(executable, constructor_args) + } + } + + fn register_contract_with_source( + &self, + executable: xdr::ContractExecutable, + constructor_args: Vec, + ) -> Address { + let args_vec: std::vec::Vec = + constructor_args.iter().map(|v| v.into_val(self)).collect(); + let constructor_args = args_vec.try_into().unwrap(); + let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap(); + self.env_impl + .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager) + .unwrap(); + let create_result = self + .env_impl + .invoke_function(xdr::HostFunction::CreateContractV2( + xdr::CreateContractArgsV2 { + contract_id_preimage: xdr::ContractIdPreimage::Address( + xdr::ContractIdPreimageFromAddress { + address: xdr::ScAddress::Contract(xdr::ContractId(xdr::Hash( + self.with_generator(|mut g| g.address()), + ))), + salt: xdr::Uint256([0; 32]), + }, + ), + executable, + constructor_args, + }, + )); + + self.env_impl.set_auth_manager(prev_auth_manager).unwrap(); + + create_result.unwrap().try_into_val(self).unwrap() + } + + /// Set authorizations and signatures in the environment which will be + /// consumed by contracts when they invoke [`Address::require_auth`] or + /// [`Address::require_auth_for_args`] functions. + /// + /// Requires valid signatures for the authorization to be successful. + /// + /// This function can also be called on contract clients. + /// + /// To mock auth for testing, without requiring valid signatures, use + /// [`mock_all_auths`][Self::mock_all_auths] or + /// [`mock_auths`][Self::mock_auths]. If mocking of auths is enabled, + /// calling [`set_auths`][Self::set_auths] disables any mocking. + pub fn set_auths(&self, auths: &[SorobanAuthorizationEntry]) { + self.env_impl + .set_authorization_entries(auths.to_vec()) + .unwrap(); + } + + /// Mock authorizations in the environment which will cause matching invokes + /// of [`Address::require_auth`] and [`Address::require_auth_for_args`] to + /// pass. + /// + /// This function can also be called on contract clients. + /// + /// Authorizations not matching a mocked auth will fail. + /// + /// To mock all auths, use [`mock_all_auths`][Self::mock_all_auths]. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; + /// + /// #[contract] + /// pub struct HelloContract; + /// + /// #[contractimpl] + /// impl HelloContract { + /// pub fn hello(env: Env, from: Address) { + /// from.require_auth(); + /// // TODO + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(HelloContract, ()); + /// + /// let client = HelloContractClient::new(&env, &contract_id); + /// let addr = Address::generate(&env); + /// client.mock_auths(&[ + /// MockAuth { + /// address: &addr, + /// invoke: &MockAuthInvoke { + /// contract: &contract_id, + /// fn_name: "hello", + /// args: (&addr,).into_val(&env), + /// sub_invokes: &[], + /// }, + /// }, + /// ]).hello(&addr); + /// } + /// ``` + pub fn mock_auths(&self, auths: &[MockAuth]) { + for a in auths { + self.register_at(a.address, MockAuthContract, ()); + } + let auths = auths + .iter() + .cloned() + .map(Into::into) + .collect::>(); + self.env_impl.set_authorization_entries(auths).unwrap(); + } + + /// Mock all calls to the [`Address::require_auth`] and + /// [`Address::require_auth_for_args`] functions in invoked contracts, + /// having them succeed as if authorization was provided. + /// + /// When mocking is enabled, if the [`Address`] being authorized is the + /// address of a contract, that contract's `__check_auth` function will not + /// be called, and the contract does not need to exist or be registered in + /// the test. + /// + /// When mocking is enabled, if the [`Address`] being authorized is the + /// address of an account, the account does not need to exist. + /// + /// This function can also be called on contract clients. + /// + /// To disable mocking, see [`set_auths`][Self::set_auths]. + /// + /// To access a list of auths that have occurred, see [`auths`][Self::auths]. + /// + /// It is not currently possible to mock a subset of auths. + /// + /// A test that uses `mock_all_auths` without verifying the resulting + /// authorization tree via [`auths`][Self::auths] can pass even when a contract + /// is missing a `require_auth` check. Use [`auths`][Self::auths] after + /// the contract call to assert that the expected authorizations were required. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, Env, Address, IntoVal, symbol_short}; + /// use soroban_sdk::testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}; + /// + /// #[contract] + /// pub struct HelloContract; + /// + /// #[contractimpl] + /// impl HelloContract { + /// pub fn hello(env: Env, from: Address) { + /// from.require_auth(); + /// // TODO + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(HelloContract, ()); + /// + /// env.mock_all_auths(); + /// + /// let client = HelloContractClient::new(&env, &contract_id); + /// let addr = Address::generate(&env); + /// client.hello(&addr); + /// + /// // Verify that the expected authorization was required. + /// assert_eq!( + /// env.auths(), + /// [( + /// addr.clone(), + /// AuthorizedInvocation { + /// function: AuthorizedFunction::Contract(( + /// contract_id, + /// symbol_short!("hello"), + /// (&addr,).into_val(&env), + /// )), + /// sub_invocations: [].into(), + /// } + /// )] + /// ); + /// } + /// ``` + pub fn mock_all_auths(&self) { + self.env_impl.switch_to_recording_auth(true).unwrap(); + } + + /// A version of [`mock_all_auths`][Self::mock_all_auths] that allows authorizations that are not + /// present in the root invocation. + /// + /// Refer to [`mock_all_auths`][Self::mock_all_auths] documentation for general information and + /// prefer using [`mock_all_auths`][Self::mock_all_auths] unless non-root authorization is required. + /// + /// The only difference from [`mock_all_auths`][Self::mock_all_auths] is that this won't return an + /// error when `require_auth` hasn't been called in the root invocation for + /// any given address. This is useful to test contracts that bundle calls to + /// another contract without atomicity requirements (i.e. any contract call + /// can be frontrun). + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _}; + /// + /// #[contract] + /// pub struct ContractA; + /// + /// #[contractimpl] + /// impl ContractA { + /// pub fn do_auth(env: Env, addr: Address) { + /// addr.require_auth(); + /// } + /// } + /// #[contract] + /// pub struct ContractB; + /// + /// #[contractimpl] + /// impl ContractB { + /// pub fn call_a(env: Env, contract_a: Address, addr: Address) { + /// // Notice there is no `require_auth` call here. + /// ContractAClient::new(&env, &contract_a).do_auth(&addr); + /// } + /// } + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_a = env.register(ContractA, ()); + /// let contract_b = env.register(ContractB, ()); + /// // The regular `env.mock_all_auths()` would result in the call + /// // failure. + /// env.mock_all_auths_allowing_non_root_auth(); + /// + /// let client = ContractBClient::new(&env, &contract_b); + /// let addr = Address::generate(&env); + /// client.call_a(&contract_a, &addr); + /// } + /// ``` + pub fn mock_all_auths_allowing_non_root_auth(&self) { + self.env_impl.switch_to_recording_auth(false).unwrap(); + } + + /// Returns a list of authorization trees that were seen during the last + /// contract or authorized host function invocation. + /// + /// Use this in tests to verify that the expected authorizations with the + /// expected arguments are required. + /// + /// The return value is a vector of authorizations represented by tuples of + /// `(address, AuthorizedInvocation)`. `AuthorizedInvocation` describes the + /// tree of `require_auth_for_args(address, args)` from the contract + /// functions (or `require_auth` with all the arguments of the function + /// invocation). It also might contain the authorized host functions ( + /// currently CreateContract is the only such function) in case if + /// corresponding host functions have been called. + /// + /// Refer to documentation for `AuthorizedInvocation` for detailed + /// information on its contents. + /// + /// The order of the returned vector is defined by the order of + /// [`Address::require_auth`] calls. Repeated calls to + /// [`Address::require_auth`] with the same address and args in the same + /// tree of contract invocations will appear only once in the vector. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, symbol_short, Address, Symbol, Env, IntoVal}; + /// + /// #[contract] + /// pub struct Contract; + /// + /// #[contractimpl] + /// impl Contract { + /// pub fn transfer(env: Env, address: Address, amount: i128) { + /// address.require_auth(); + /// } + /// pub fn transfer2(env: Env, address: Address, amount: i128) { + /// address.require_auth_for_args((amount / 2,).into_val(&env)); + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(Contract, ()); + /// let client = ContractClient::new(&env, &contract_id); + /// env.mock_all_auths(); + /// let address = Address::generate(&env); + /// client.transfer(&address, &1000_i128); + /// assert_eq!( + /// env.auths(), + /// [( + /// address.clone(), + /// AuthorizedInvocation { + /// function: AuthorizedFunction::Contract(( + /// client.address.clone(), + /// symbol_short!("transfer"), + /// (&address, 1000_i128,).into_val(&env) + /// )), + /// sub_invocations: [].into() + /// } + /// )] + /// ); + /// + /// client.transfer2(&address, &1000_i128); + /// assert_eq!( + /// env.auths(), + /// [( + /// address.clone(), + /// AuthorizedInvocation { + /// function: AuthorizedFunction::Contract(( + /// client.address.clone(), + /// symbol_short!("transfer2"), + /// // `transfer2` requires auth for (amount / 2) == (1000 / 2) == 500. + /// (500_i128,).into_val(&env) + /// )), + /// sub_invocations: [].into() + /// } + /// )] + /// ); + /// } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + pub fn auths(&self) -> std::vec::Vec<(Address, AuthorizedInvocation)> { + (*self.test_state.auth_snapshot) + .borrow() + .0 + .last() + .cloned() + .unwrap_or_default() + .into_iter() + .map(|(sc_addr, invocation)| { + ( + xdr::ScVal::Address(sc_addr).try_into_val(self).unwrap(), + AuthorizedInvocation::from_xdr(self, &invocation), + ) + }) + .collect() + } + + /// Invokes the special `__check_auth` function of contracts that implement + /// the custom account interface. + /// + /// `__check_auth` can't be called outside of the host-managed `require_auth` + /// calls. This test utility allows testing custom account contracts without + /// the need to setup complex contract call trees and enabling the enforcing + /// auth on the host side. + /// + /// This function requires to provide the template argument for error. Use + /// `soroban_sdk::Error` if `__check_auth` doesn't return a special + /// contract error and use the error with `contracterror` attribute + /// otherwise. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contracterror, contractimpl, testutils::{Address as _, BytesN as _}, vec, auth::Context, BytesN, Env, Vec, Val}; + /// + /// #[contracterror] + /// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] + /// #[repr(u32)] + /// pub enum NoopAccountError { + /// SomeError = 1, + /// } + /// #[contract] + /// struct NoopAccountContract; + /// #[contractimpl] + /// impl NoopAccountContract { + /// + /// #[allow(non_snake_case)] + /// pub fn __check_auth( + /// _env: Env, + /// _signature_payload: BytesN<32>, + /// signature: Val, + /// _auth_context: Vec, + /// ) -> Result<(), NoopAccountError> { + /// if signature.is_void() { + /// Err(NoopAccountError::SomeError) + /// } else { + /// Ok(()) + /// } + /// } + /// } + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let e: Env = Default::default(); + /// let account_contract = NoopAccountContractClient::new(&e, &e.register(NoopAccountContract, ())); + /// // Non-successful call of `__check_auth` with a `contracterror` error. + /// assert_eq!( + /// e.try_invoke_contract_check_auth::( + /// &account_contract.address, + /// &BytesN::from_array(&e, &[0; 32]), + /// ().into(), + /// &vec![&e], + /// ), + /// // The inner `Result` is for conversion error and will be Ok + /// // as long as a valid error type used. + /// Err(Ok(NoopAccountError::SomeError)) + /// ); + /// // Successful call of `__check_auth` with a `soroban_sdk::InvokeError` + /// // error - this should be compatible with any error type. + /// assert_eq!( + /// e.try_invoke_contract_check_auth::( + /// &account_contract.address, + /// &BytesN::from_array(&e, &[0; 32]), + /// 0_i32.into(), + /// &vec![&e], + /// ), + /// Ok(()) + /// ); + /// } + /// ``` + pub fn try_invoke_contract_check_auth( + &self, + contract: &Address, + signature_payload: &BytesN<32>, + signature: Val, + auth_context: &Vec, + ) -> Result<(), Result> + where + E: TryFrom, + E::Error: Into, + { + let args = Vec::from_array( + self, + [signature_payload.to_val(), signature, auth_context.to_val()], + ); + let res = self + .host() + .call_account_contract_check_auth(contract.to_object(), args.to_object()); + match res { + Ok(rv) => Ok(rv.into_val(self)), + Err(e) => Err(e.error.try_into().map_err(Into::into)), + } + } + + fn register_contract_with_contract_id_and_executable( + &self, + contract_address: &Address, + executable: xdr::ContractExecutable, + constructor_args: Vec, + ) { + let contract_id = contract_address.contract_id(); + let data_key = xdr::ScVal::LedgerKeyContractInstance; + let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData { + contract: xdr::ScAddress::Contract(contract_id.clone()), + key: data_key.clone(), + durability: xdr::ContractDataDurability::Persistent, + })); + + let instance = xdr::ScContractInstance { + executable, + storage: Default::default(), + }; + + let entry = Rc::new(LedgerEntry { + ext: xdr::LedgerEntryExt::V0, + last_modified_ledger_seq: 0, + data: xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry { + contract: xdr::ScAddress::Contract(contract_id.clone()), + key: data_key, + val: xdr::ScVal::ContractInstance(instance), + durability: xdr::ContractDataDurability::Persistent, + ext: xdr::ExtensionPoint::V0, + }), + }); + let live_until_ledger = self.ledger().sequence() + 1; + self.host() + .add_ledger_entry(&key, &entry, Some(live_until_ledger)) + .unwrap(); + self.env_impl + .call_constructor_for_stored_contract_unsafe(&contract_id, constructor_args.to_object()) + .unwrap(); + } + + /// Run the function as if executed by the given contract ID. + /// + /// Used to write or read contract data, or take other actions in tests for + /// setting up tests or asserting on internal state. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, Env, Symbol}; + /// + /// #[contract] + /// pub struct HelloContract; + /// + /// #[contractimpl] + /// impl HelloContract { + /// pub fn set_storage(env: Env, key: Symbol, val: Symbol) { + /// env.storage().persistent().set(&key, &val); + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(HelloContract, ()); + /// let client = HelloContractClient::new(&env, &contract_id); + /// + /// let key = Symbol::new(&env, "foo"); + /// let val = Symbol::new(&env, "bar"); + /// + /// // Set storage using the contract + /// client.set_storage(&key, &val); + /// + /// // Successfully read the storage key + /// let result = env.as_contract(&contract_id, || { + /// env.storage() + /// .persistent() + /// .get::(&key) + /// .unwrap() + /// }); + /// assert_eq!(result, val); + /// } + /// ``` + pub fn as_contract(&self, id: &Address, f: impl FnOnce() -> T) -> T { + let id = id.contract_id(); + let func = Symbol::from_small_str(""); + let mut t: Option = None; + self.env_impl + .with_test_contract_frame(id, func, || { + t = Some(f()); + Ok(().into()) + }) + .unwrap(); + t.unwrap() + } + + /// Run the function as if executed by the given contract ID. Returns an + /// error if the function execution fails for any reason. + /// + /// Used to write or read contract data, or take other actions in tests for + /// setting up tests or asserting on internal state. + /// + /// ### Examples + /// ``` + /// use soroban_sdk::{contract, contractimpl, xdr::{ScErrorCode, ScErrorType}, Env, Error, Symbol}; + /// + /// #[contract] + /// pub struct HelloContract; + /// + /// #[contractimpl] + /// impl HelloContract { + /// pub fn set_storage(env: Env, key: Symbol, val: Symbol) { + /// env.storage().persistent().set(&key, &val); + /// } + /// } + /// + /// #[test] + /// fn test() { + /// # } + /// # fn main() { + /// let env = Env::default(); + /// let contract_id = env.register(HelloContract, ()); + /// let client = HelloContractClient::new(&env, &contract_id); + /// + /// let key = Symbol::new(&env, "foo"); + /// let val = Symbol::new(&env, "bar"); + /// + /// // Set storage using the contract + /// client.set_storage(&key, &val); + /// + /// // Successfully read the storage key + /// let result = env.try_as_contract::(&contract_id, || { + /// env.storage() + /// .persistent() + /// .get::(&key) + /// .unwrap() + /// }); + /// assert_eq!(result, Ok(val)); + /// + /// // Attempting to extend TTL of a non-existent key throws an error + /// let new_key = Symbol::new(&env, "baz"); + /// let result = env.try_as_contract(&contract_id, || { + /// env.storage().persistent().extend_ttl(&new_key, 1, 100); + /// }); + /// assert_eq!( + /// result, + /// Err(Ok(Error::from_type_and_code( + /// ScErrorType::Storage, + /// ScErrorCode::MissingValue + /// ))) + /// ); + /// } + /// ``` + pub fn try_as_contract( + &self, + id: &Address, + f: impl FnOnce() -> T, + ) -> Result> + where + E: TryFrom, + E::Error: Into, + { + let id = id.contract_id(); + let func = Symbol::from_small_str(""); + let mut t: Option = None; + let result = self.env_impl.try_with_test_contract_frame(id, func, || { + t = Some(f()); + Ok(().into()) + }); + + match result { + Ok(_) => Ok(t.unwrap()), + Err(e) => Err(E::try_from(e.error).map_err(Into::into)), + } + } + + /// Creates a new Env loaded with the [`Snapshot`]. + /// + /// The ledger info and state in the snapshot are loaded into the Env. + /// + /// Events, as an output source only, are not loaded into the Env. + pub fn from_snapshot(s: Snapshot) -> Env { + Env::new_for_testutils( + EnvTestConfig::default(), + Rc::new(s.ledger.clone()), + Some(Rc::new(RefCell::new(s.generators))), + Some(s.ledger.ledger_info()), + Some(Rc::new(s.ledger.clone())), + ) + } + + /// Creates a new Env loaded with the ledger snapshot loaded from the file. + /// + /// The ledger info and state in the snapshot are loaded into the Env. + /// + /// Events, as an output source only, are not loaded into the Env. + /// + /// ### Panics + /// + /// If there is any error reading the file. + pub fn from_snapshot_file(p: impl AsRef) -> Env { + Self::from_snapshot(Snapshot::read_file(p).unwrap()) + } + + /// Create a snapshot from the Env's current state. + pub fn to_snapshot(&self) -> Snapshot { + Snapshot { + generators: (*self.test_state.generators).borrow().clone(), + auth: (*self.test_state.auth_snapshot).borrow().clone(), + ledger: self.to_ledger_snapshot(), + events: self.to_events_snapshot(), + } + } + + /// Create a snapshot file from the Env's current state. + /// + /// ### Panics + /// + /// If there is any error writing the file. + pub fn to_snapshot_file(&self, p: impl AsRef) { + self.to_snapshot().write_file(p).unwrap(); + } + + /// Creates a new Env loaded with the snapshot source. + /// + /// The ledger info and state from the snapshot source are loaded into the Env. + pub fn from_ledger_snapshot(input: impl Into) -> Env { + let SnapshotSourceInput { + source, + ledger_info, + snapshot, + } = input.into(); + + Env::new_for_testutils( + EnvTestConfig::default(), // TODO: Allow setting the config. + source, + None, + ledger_info, + snapshot, + ) + } + + /// Creates a new Env loaded with the ledger snapshot loaded from the file. + /// + /// ### Panics + /// + /// If there is any error reading the file. + pub fn from_ledger_snapshot_file(p: impl AsRef) -> Env { + Self::from_ledger_snapshot(LedgerSnapshot::read_file(p).unwrap()) + } + + /// Create a snapshot from the Env's current state. + pub fn to_ledger_snapshot(&self) -> LedgerSnapshot { + let snapshot = self.test_state.snapshot.clone().unwrap_or_default(); + let mut snapshot = (*snapshot).clone(); + snapshot.set_ledger_info(self.ledger().get()); + snapshot.update_entries(&self.host().get_stored_entries().unwrap()); + snapshot + } + + /// Create a snapshot file from the Env's current state. + /// + /// ### Panics + /// + /// If there is any error writing the file. + pub fn to_ledger_snapshot_file(&self, p: impl AsRef) { + self.to_ledger_snapshot().write_file(p).unwrap(); + } + + /// Create an events snapshot from the Env's current state. + pub(crate) fn to_events_snapshot(&self) -> EventsSnapshot { + EventsSnapshot( + self.host() + .get_events() + .unwrap() + .0 + .into_iter() + .filter(|e| match e.event.type_ { + // Keep only system and contract events, because event + // snapshots are used in test snapshots, and intended to be + // stable over time because the goal is to record meaningful + // observable behaviors. Diagnostic events are observable, + // but events have no stability guarantees and are intended + // to be used by developers when debugging, tracing, and + // observing, not by systems that integrate. + xdr::ContractEventType::System | xdr::ContractEventType::Contract => true, + xdr::ContractEventType::Diagnostic => false, + }) + .map(Into::into) + .collect(), + ) + } + + /// Get the budget that tracks the resources consumed for the environment. + #[deprecated(note = "use cost_estimate().budget()")] + pub fn budget(&self) -> Budget { + Budget::new(self.env_impl.budget_cloned()) + } +} + +#[cfg(any(test, feature = "testutils"))] +impl Drop for Env { + fn drop(&mut self) { + // If the env impl (Host) is finishable, that means this Env is the last + // Env to hold a reference to the Host. The Env should only write a test + // snapshot at that point when no other references to the host exist, + // because it is only when there are no other references that the host + // is being dropped. + if self.env_impl.can_finish() && self.test_state.config.capture_snapshot_at_drop { + self.to_test_snapshot_file(); + } + } +} + +#[doc(hidden)] +#[cfg(any(test, feature = "testutils"))] +impl Env { + /// Create a snapshot file for the currently executing test. + /// + /// Writes the file to the `test_snapshots/{test-name}.N.json` path where + /// `N` is incremented for each unique `Env` in the test. + /// + /// Use to record the observable behavior of a test, and changes to that + /// behavior over time. Commit the test snapshot file to version control and + /// watch for changes in it on contract change, SDK upgrade, protocol + /// upgrade, and other important events. + /// + /// No file will be created if the environment has no meaningful data such + /// as stored entries or events. + /// + /// ### Panics + /// + /// If there is any error writing the file. + pub(crate) fn to_test_snapshot_file(&self) { + let snapshot = self.to_snapshot(); + + // Don't write a snapshot that has no data in it. + if snapshot.ledger.entries().into_iter().count() == 0 + && snapshot.events.0.is_empty() + && snapshot.auth.0.is_empty() + { + return; + } + + // Determine path to write test snapshots to. + let Some(test_name) = &self.test_state.test_name else { + // If there's no test name, we're not in a test context, so don't write snapshots. + return; + }; + let number = self.test_state.number; + // Break up the test name into directories, using :: as the separator. + // The :: module separator cannot be written into the filename because + // some operating systems (e.g. Windows) do not allow the : character in + // filenames. + let test_name_path = test_name + .split("::") + .map(|p| std::path::Path::new(p).to_path_buf()) + .reduce(|p0, p1| p0.join(p1)) + .expect("test name to not be empty"); + let dir = std::path::Path::new("test_snapshots"); + let p = dir + .join(&test_name_path) + .with_extension(format!("{number}.json")); + + // Write test snapshots to file. + eprintln!("Writing test snapshot file for test {test_name:?} to {p:?}."); + snapshot.write_file(p).unwrap(); + } +} + +#[doc(hidden)] +impl internal::EnvBase for Env { + type Error = Infallible; + + // This exists to allow code in conversion paths to upgrade an Error to an + // Env::Error with some control granted to the underlying Env (and panic + // paths kept out of the host). We delegate this to our env_impl and then, + // since our own Error type is Infallible, immediately throw it into either + // the env_impl's Error escalation path (if testing), or just plain panic. + #[cfg(not(target_family = "wasm"))] + fn error_from_error_val(&self, e: crate::Error) -> Self::Error { + let host_err = self.env_impl.error_from_error_val(e); + #[cfg(any(test, feature = "testutils"))] + self.env_impl.escalate_error_to_panic(host_err); + #[cfg(not(any(test, feature = "testutils")))] + panic!("{:?}", host_err); + } + + // When targeting wasm we don't even need to do that, just delegate to + // the Guest's impl, which calls core::arch::wasm32::unreachable. + #[cfg(target_family = "wasm")] + #[allow(unreachable_code)] + fn error_from_error_val(&self, e: crate::Error) -> Self::Error { + self.env_impl.error_from_error_val(e) + } + + fn check_protocol_version_lower_bound(&self, v: u32) -> Result<(), Self::Error> { + Ok(self + .env_impl + .check_protocol_version_lower_bound(v) + .unwrap_optimized()) + } + + fn check_protocol_version_upper_bound(&self, v: u32) -> Result<(), Self::Error> { + Ok(self + .env_impl + .check_protocol_version_upper_bound(v) + .unwrap_optimized()) + } + + // Note: the function `escalate_error_to_panic` only exists _on the `Env` + // trait_ when the feature `soroban-env-common/testutils` is enabled. This + // is because the host wants to never have this function even _compiled in_ + // when building for production, as it might be accidentally called (we have + // mistakenly done so with conversion and comparison traits in the past). + // + // As a result, we only implement it here (fairly meaninglessly) when we're + // in `cfg(test)` (which enables `soroban-env-host/testutils` thus + // `soroban-env-common/testutils`) or when we've had our own `testutils` + // feature enabled (which does the same). + // + // See the `internal::reject_err` functions above for more detail about what + // it actually does (when implemented for real, on the host). In this + // not-very-serious impl, since `Self::Error` is `Infallible`, this instance + // can never actually be called and so its body is just a trivial + // transformation from one empty type to another, for Type System Reasons. + #[cfg(any(test, feature = "testutils"))] + fn escalate_error_to_panic(&self, e: Self::Error) -> ! { + match e {} + } + + fn bytes_copy_from_slice( + &self, + b: BytesObject, + b_pos: U32Val, + slice: &[u8], + ) -> Result { + Ok(self + .env_impl + .bytes_copy_from_slice(b, b_pos, slice) + .unwrap_optimized()) + } + + fn bytes_copy_to_slice( + &self, + b: BytesObject, + b_pos: U32Val, + slice: &mut [u8], + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .bytes_copy_to_slice(b, b_pos, slice) + .unwrap_optimized()) + } + + fn bytes_new_from_slice(&self, slice: &[u8]) -> Result { + Ok(self.env_impl.bytes_new_from_slice(slice).unwrap_optimized()) + } + + fn log_from_slice(&self, msg: &str, args: &[Val]) -> Result { + Ok(self.env_impl.log_from_slice(msg, args).unwrap_optimized()) + } + + fn string_copy_to_slice( + &self, + b: StringObject, + b_pos: U32Val, + slice: &mut [u8], + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .string_copy_to_slice(b, b_pos, slice) + .unwrap_optimized()) + } + + fn symbol_copy_to_slice( + &self, + b: SymbolObject, + b_pos: U32Val, + mem: &mut [u8], + ) -> Result<(), Self::Error> { + Ok(self + .env_impl + .symbol_copy_to_slice(b, b_pos, mem) + .unwrap_optimized()) + } + + fn string_new_from_slice(&self, slice: &[u8]) -> Result { + Ok(self + .env_impl + .string_new_from_slice(slice) + .unwrap_optimized()) + } + + fn symbol_new_from_slice(&self, slice: &[u8]) -> Result { + Ok(self + .env_impl + .symbol_new_from_slice(slice) + .unwrap_optimized()) + } + + fn map_new_from_slices(&self, keys: &[&str], vals: &[Val]) -> Result { + Ok(self + .env_impl + .map_new_from_slices(keys, vals) + .unwrap_optimized()) + } + + fn map_unpack_to_slice( + &self, + map: MapObject, + keys: &[&str], + vals: &mut [Val], + ) -> Result { + Ok(self + .env_impl + .map_unpack_to_slice(map, keys, vals) + .unwrap_optimized()) + } + + fn vec_new_from_slice(&self, vals: &[Val]) -> Result { + Ok(self.env_impl.vec_new_from_slice(vals).unwrap_optimized()) + } + + fn vec_unpack_to_slice(&self, vec: VecObject, vals: &mut [Val]) -> Result { + Ok(self + .env_impl + .vec_unpack_to_slice(vec, vals) + .unwrap_optimized()) + } + + fn symbol_index_in_strs(&self, key: Symbol, strs: &[&str]) -> Result { + Ok(self + .env_impl + .symbol_index_in_strs(key, strs) + .unwrap_optimized()) + } +} + +/////////////////////////////////////////////////////////////////////////////// +/// X-macro use: impl Env for SDK's Env +/////////////////////////////////////////////////////////////////////////////// + +// This is a helper macro used only by impl_env_for_sdk below. It consumes a +// token-tree of the form: +// +// {fn $fn_id:ident $args:tt -> $ret:ty} +// +// and produces the the corresponding method definition to be used in the +// SDK's Env implementation of the Env (calling through to the corresponding +// guest or host implementation). +macro_rules! sdk_function_helper { + {$mod_id:ident, fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty} + => + { + fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error> { + internal::reject_err(&self.env_impl, self.env_impl.$fn_id($($arg),*)) + } + }; +} + +// This is a callback macro that pattern-matches the token-tree passed by the +// x-macro (call_macro_with_all_host_functions) and produces a suite of +// forwarding-method definitions, which it places in the body of the declaration +// of the implementation of Env for the SDK's Env. +macro_rules! impl_env_for_sdk { + { + $( + // This outer pattern matches a single 'mod' block of the token-tree + // passed from the x-macro to this macro. It is embedded in a `$()*` + // pattern-repetition matcher so that it will match all provided + // 'mod' blocks provided. + $(#[$mod_attr:meta])* + mod $mod_id:ident $mod_str:literal + { + $( + // This inner pattern matches a single function description + // inside a 'mod' block in the token-tree passed from the + // x-macro to this macro. It is embedded in a `$()*` + // pattern-repetition matcher so that it will match all such + // descriptions. + $(#[$fn_attr:meta])* + { $fn_str:literal, $($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident $args:tt -> $ret:ty } + )* + } + )* + } + + => // The part of the macro above this line is a matcher; below is its expansion. + + { + // This macro expands to a single item: the implementation of Env for + // the SDK's Env struct used by client contract code running in a WASM VM. + #[doc(hidden)] + impl internal::Env for Env + { + $( + $( + // This invokes the guest_function_helper! macro above + // passing only the relevant parts of the declaration + // matched by the inner pattern above. It is embedded in two + // nested `$()*` pattern-repetition expanders that + // correspond to the pattern-repetition matchers in the + // match section, but we ignore the structure of the 'mod' + // block repetition-level from the outer pattern in the + // expansion, flattening all functions from all 'mod' blocks + // into the implementation of Env for Guest. + sdk_function_helper!{$mod_id, fn $fn_id $args -> $ret} + )* + )* + } + }; +} + +// Here we invoke the x-macro passing generate_env_trait as its callback macro. +internal::call_macro_with_all_host_functions! { impl_env_for_sdk } diff --git a/temp_sdk/soroban-sdk-26.0.1/src/error.rs b/temp_sdk/soroban-sdk-26.0.1/src/error.rs new file mode 100644 index 0000000..a7386e4 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/error.rs @@ -0,0 +1,37 @@ +use core::convert::Infallible; + +use crate::xdr; + +/// InvokeError captures errors returned from the invocation of another +/// contract. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum InvokeError { + /// Abort occurs if the invoke contract panicks with a [`panic!`], or a host + /// function of the environment has a failure, or a runtime error occurs. + Abort, + /// Contract error occurs if the invoked contract function exited returning + /// an error or called [`panic_with_error!`][crate::panic_with_error!] with + /// a [`contracterror`][crate::contracterror]. + /// + /// If the contract defines a [`contracterror`][crate::contracterror] type + /// as part of its interface, this variant of the error will be convertible + /// to that type, but if that conversion failed then this variant of the + /// error would be used to represent the error. + Contract(u32), +} + +impl From for InvokeError { + fn from(e: crate::Error) -> Self { + if e.is_type(xdr::ScErrorType::Contract) { + InvokeError::Contract(e.get_code()) + } else { + InvokeError::Abort + } + } +} + +impl From for InvokeError { + fn from(_: Infallible) -> Self { + unreachable!() + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/events.rs b/temp_sdk/soroban-sdk-26.0.1/src/events.rs new file mode 100644 index 0000000..a818d88 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/events.rs @@ -0,0 +1,162 @@ +//! Events contains types for publishing contract events. +use core::fmt::Debug; + +#[cfg(doc)] +use crate::{contracttype, Bytes, Map}; +use crate::{env::internal, unwrap::UnwrapInfallible, Env, IntoVal, Val, Vec}; + +// TODO: consolidate with host::events::TOPIC_BYTES_LENGTH_LIMIT +const TOPIC_BYTES_LENGTH_LIMIT: u32 = 32; + +/// Events publishes events for the currently executing contract. +/// +/// ``` +/// use soroban_sdk::Env; +/// +/// # use soroban_sdk::{contract, contractimpl, vec, map, Val, BytesN}; +/// # +/// # #[contract] +/// # pub struct Contract; +/// # +/// # #[contractimpl] +/// # impl Contract { +/// # pub fn f(env: Env) { +/// let event = env.events(); +/// let data = map![&env, (1u32, 2u32)]; +/// // topics can be represented with tuple up to a certain length +/// let topics0 = (); +/// let topics1 = (0u32,); +/// let topics2 = (0u32, 1u32); +/// let topics3 = (0u32, 1u32, 2u32); +/// let topics4 = (0u32, 1u32, 2u32, 3u32); +/// // topics can also be represented with a `Vec` with no length limit +/// let topics5 = vec![&env, 4u32, 5u32, 6u32, 7u32, 8u32]; +/// event.publish(topics0, data.clone()); +/// event.publish(topics1, data.clone()); +/// event.publish(topics2, data.clone()); +/// event.publish(topics3, data.clone()); +/// event.publish(topics4, data.clone()); +/// event.publish(topics5, data.clone()); +/// # } +/// # } +/// +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// # let env = Env::default(); +/// # let contract_id = env.register(Contract, ()); +/// # ContractClient::new(&env, &contract_id).f(); +/// # } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +#[derive(Clone)] +pub struct Events(Env); + +impl Debug for Events { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Events") + } +} + +#[cfg(any(test, feature = "testutils"))] +use crate::{testutils, xdr, FromVal}; + +pub trait Event { + fn topics(&self, env: &Env) -> Vec; + fn data(&self, env: &Env) -> Val; + + fn publish(&self, env: &Env) { + env.events().publish_event(self); + } + + /// Convert this event and the given contract_id into a [`xdr::ContractEvent`] object. + /// Used to compare Events to emitted events in tests. + #[cfg(any(test, feature = "testutils"))] + fn to_xdr(&self, env: &Env, contract_id: &crate::Address) -> xdr::ContractEvent { + xdr::ContractEvent { + ext: xdr::ExtensionPoint::V0, + type_: xdr::ContractEventType::Contract, + contract_id: Some(contract_id.contract_id()), + body: xdr::ContractEventBody::V0(xdr::ContractEventV0 { + topics: self.topics(env).into(), + data: xdr::ScVal::from_val(env, &self.data(env)), + }), + } + } +} + +pub trait Topics: IntoVal> {} + +impl Topics for Vec {} + +impl Events { + #[inline(always)] + pub(crate) fn env(&self) -> &Env { + &self.0 + } + + #[inline(always)] + pub(crate) fn new(env: &Env) -> Events { + Events(env.clone()) + } + + /// Publish an event defined using the [`contractevent`][crate::contractevent] macro. + #[inline(always)] + pub fn publish_event(&self, e: &(impl Event + ?Sized)) { + let env = self.env(); + internal::Env::contract_event(env, e.topics(env).to_object(), e.data(env)) + .unwrap_infallible(); + } + + /// Publish an event. + /// + /// Consider using [`contractevent`][crate::contractevent] instead of this function. + /// + /// Event data is specified in `data`. Data may be any value or + /// type, including types defined by contracts using [contracttype]. + /// + /// Event topics must not contain: + /// + /// - [Vec] + /// - [Map] + /// - [Bytes]/[BytesN][crate::BytesN] longer than 32 bytes + /// - [contracttype] + #[deprecated(note = "use the #[contractevent] macro on a contract event type")] + #[inline(always)] + pub fn publish(&self, topics: T, data: D) + where + T: Topics, + D: IntoVal, + { + let env = self.env(); + internal::Env::contract_event(env, topics.into_val(env).to_object(), data.into_val(env)) + .unwrap_infallible(); + } +} + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl testutils::Events for Events { + fn all(&self) -> testutils::ContractEvents { + let env = self.env(); + let vec: std::vec::Vec = self + .env() + .host() + .get_events() + .unwrap() + .0 + .into_iter() + .filter_map(|e| { + if !e.failed_call + && e.event.type_ == xdr::ContractEventType::Contract + && e.event.contract_id.is_some() + { + Some(e.event) + } else { + None + } + }) + .collect(); + testutils::ContractEvents::new(&env, vec) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs b/temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs new file mode 100644 index 0000000..a875902 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs @@ -0,0 +1,46 @@ +//! IntoValForContractFn is an internal trait that is used by code generated +//! for the export of contract functions. The generated code calls the trait to +//! convert return values from their respective SDK types into Val. +//! +//! The trait has a blanket implementation for all types that already implement +//! IntoVal. +//! +//! When the `experimental_spec_shaking_v2` feature is enabled, this trait also +//! calls `SpecShakingMarker::spec_shaking_marker()` to ensure that type specs +//! are included in the WASM when types are used at external boundaries +//! (function return values). + +use crate::{Env, IntoVal, Val}; + +#[doc(hidden)] +#[deprecated( + note = "IntoValForContractFn is an internal trait and is not safe to use or implement" +)] +pub trait IntoValForContractFn { + fn into_val_for_contract_fn(self, env: &Env) -> Val; +} + +#[cfg(feature = "experimental_spec_shaking_v2")] +#[doc(hidden)] +#[allow(deprecated)] +impl IntoValForContractFn for T +where + T: IntoVal + crate::SpecShakingMarker, +{ + fn into_val_for_contract_fn(self, env: &Env) -> Val { + T::spec_shaking_marker(); + self.into_val(env) + } +} + +#[cfg(not(feature = "experimental_spec_shaking_v2"))] +#[doc(hidden)] +#[allow(deprecated)] +impl IntoValForContractFn for T +where + T: IntoVal, +{ + fn into_val_for_contract_fn(self, env: &Env) -> Val { + self.into_val(env) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/iter.rs b/temp_sdk/soroban-sdk-26.0.1/src/iter.rs new file mode 100644 index 0000000..8dd6d5e --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/iter.rs @@ -0,0 +1,87 @@ +//! Iterators for use with collections like [Map], [Vec]. +//! +//! Collections are not guaranteed to contain values of the expected type as +//! they are stored on the host as [Val]s, so two iterators are provided: +//! +//! - **`try_iter()`** returns an iterator that yields `Result` for each +//! element, allowing the caller to handle conversion errors. +//! - **`iter()`** returns an iterator that unwraps each result, +//! panicking if any element cannot be converted to the declared type. +#[cfg(doc)] +use crate::{Map, Val, Vec}; + +use core::fmt::Debug; +use core::iter::FusedIterator; +use core::marker::PhantomData; + +pub trait UnwrappedEnumerable { + fn unwrapped(self) -> UnwrappedIter; +} + +impl UnwrappedEnumerable for I +where + I: Iterator>, + E: Debug, +{ + fn unwrapped(self) -> UnwrappedIter { + UnwrappedIter { + iter: self, + item_type: PhantomData, + error_type: PhantomData, + } + } +} + +#[derive(Clone)] +pub struct UnwrappedIter { + iter: I, + item_type: PhantomData, + error_type: PhantomData, +} + +impl Iterator for UnwrappedIter +where + I: Iterator>, + E: Debug, +{ + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option { + self.iter.next().map(Result::unwrap) + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl DoubleEndedIterator for UnwrappedIter +where + I: Iterator> + DoubleEndedIterator, + E: Debug, +{ + #[inline(always)] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(Result::unwrap) + } +} + +impl FusedIterator for UnwrappedIter +where + I: Iterator> + FusedIterator, + E: Debug, +{ +} + +impl ExactSizeIterator for UnwrappedIter +where + I: Iterator> + ExactSizeIterator, + E: Debug, +{ + #[inline(always)] + fn len(&self) -> usize { + self.iter.len() + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/ledger.rs b/temp_sdk/soroban-sdk-26.0.1/src/ledger.rs new file mode 100644 index 0000000..52d251e --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/ledger.rs @@ -0,0 +1,184 @@ +//! Ledger contains types for retrieving information about the current ledger. +use crate::{env::internal, unwrap::UnwrapInfallible, BytesN, Env, TryIntoVal}; + +/// Ledger retrieves information about the current ledger. +/// +/// For more details about the ledger and the ledger header that the values in the Ledger are derived from, see: +/// - +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::Env; +/// +/// # use soroban_sdk::{contract, contractimpl, BytesN}; +/// # +/// # #[contract] +/// # pub struct Contract; +/// # +/// # #[contractimpl] +/// # impl Contract { +/// # pub fn f(env: Env) { +/// let ledger = env.ledger(); +/// +/// let sequence = ledger.sequence(); +/// let timestamp = ledger.timestamp(); +/// let network_id = ledger.network_id(); +/// # } +/// # } +/// # +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// # let env = Env::default(); +/// # let contract_id = env.register(Contract, ()); +/// # ContractClient::new(&env, &contract_id).f(); +/// # } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +#[derive(Clone)] +pub struct Ledger(Env); + +impl Ledger { + #[inline(always)] + pub(crate) fn env(&self) -> &Env { + &self.0 + } + + #[inline(always)] + pub(crate) fn new(env: &Env) -> Ledger { + Ledger(env.clone()) + } + + /// Returns the version of the protocol that the ledger created with. + #[deprecated(note = "Protocol version won't be available in the future")] + pub fn protocol_version(&self) -> u32 { + internal::Env::get_ledger_version(self.env()) + .unwrap_infallible() + .into() + } + + /// Returns the sequence number of the ledger. + /// + /// The sequence number is a unique number for each ledger + /// that is sequential, incremented by one for each new ledger. + pub fn sequence(&self) -> u32 { + internal::Env::get_ledger_sequence(self.env()) + .unwrap_infallible() + .into() + } + + /// Returns the maximum ledger sequence number that data can live to. + #[doc(hidden)] + pub fn max_live_until_ledger(&self) -> u32 { + internal::Env::get_max_live_until_ledger(self.env()) + .unwrap_infallible() + .into() + } + + /// Returns a unix timestamp for when the ledger was closed. + /// + /// The timestamp is the number of seconds, excluding leap seconds, that + /// have elapsed since unix epoch. Unix epoch is January 1st, 1970, at + /// 00:00:00 UTC. + /// + /// For more details see: + /// - + pub fn timestamp(&self) -> u64 { + internal::Env::get_ledger_timestamp(self.env()) + .unwrap_infallible() + .try_into_val(self.env()) + .unwrap() + } + + /// Returns the network identifier. + /// + /// This is SHA-256 hash of the network passphrase, for example + /// for the Public Network this returns: + /// > SHA256(Public Global Stellar Network ; September 2015) + /// + /// Returns for the Test Network: + /// > SHA256(Test SDF Network ; September 2015) + pub fn network_id(&self) -> BytesN<32> { + let env = self.env(); + let bin_obj = internal::Env::get_ledger_network_id(env).unwrap_infallible(); + unsafe { BytesN::<32>::unchecked_new(env.clone(), bin_obj) } + } +} + +#[cfg(any(test, feature = "testutils"))] +use crate::testutils; + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl testutils::Ledger for Ledger { + fn set(&self, li: testutils::LedgerInfo) { + let env = self.env(); + env.host().set_ledger_info(li).unwrap(); + } + + fn set_protocol_version(&self, protocol_version: u32) { + self.with_mut(|ledger_info| { + ledger_info.protocol_version = protocol_version; + }); + } + + fn set_sequence_number(&self, sequence_number: u32) { + self.with_mut(|ledger_info| { + ledger_info.sequence_number = sequence_number; + }); + } + + fn set_timestamp(&self, timestamp: u64) { + self.with_mut(|ledger_info| { + ledger_info.timestamp = timestamp; + }); + } + + fn set_network_id(&self, network_id: [u8; 32]) { + self.with_mut(|ledger_info| { + ledger_info.network_id = network_id; + }); + } + + fn set_base_reserve(&self, base_reserve: u32) { + self.with_mut(|ledger_info| { + ledger_info.base_reserve = base_reserve; + }); + } + + fn set_min_temp_entry_ttl(&self, min_temp_entry_ttl: u32) { + self.with_mut(|ledger_info| { + ledger_info.min_temp_entry_ttl = min_temp_entry_ttl; + }); + } + + fn set_min_persistent_entry_ttl(&self, min_persistent_entry_ttl: u32) { + self.with_mut(|ledger_info| { + ledger_info.min_persistent_entry_ttl = min_persistent_entry_ttl; + }); + } + + fn set_max_entry_ttl(&self, max_entry_ttl: u32) { + self.with_mut(|ledger_info| { + // For the sake of consistency across SDK methods, + // we always make TTL values to not include the current ledger. + // The actual network setting in env expects this to include + // the current ledger, so we need to add 1 here. + ledger_info.max_entry_ttl = max_entry_ttl.saturating_add(1); + }); + } + + fn get(&self) -> testutils::LedgerInfo { + let env = self.env(); + env.host().with_ledger_info(|li| Ok(li.clone())).unwrap() + } + + fn with_mut(&self, f: F) + where + F: FnMut(&mut internal::LedgerInfo), + { + let env = self.env(); + env.host().with_mut_ledger_info(f).unwrap(); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/lib.rs b/temp_sdk/soroban-sdk-26.0.1/src/lib.rs new file mode 100644 index 0000000..4b4ee96 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/lib.rs @@ -0,0 +1,1255 @@ +//! Soroban SDK supports writing smart contracts for the Wasm-powered [Soroban] smart contract +//! runtime, deployed on [Stellar]. +//! +//! ### Docs +//! +//! See [developers.stellar.org] for documentation about building smart contracts for [Stellar]. +//! +//! [developers.stellar.org]: https://developers.stellar.org +//! [Stellar]: https://stellar.org +//! [Soroban]: https://stellar.org/soroban +//! +//! ### Support +//! +//! The two most recent soroban-sdk major releases are supported with critical security fixes. +//! Critical security issues may be backported to earlier versions if practical, but not guaranteed. +//! General bugs are only fixed on, and new features are only added to, the latest major release. +//! +//! ### Features +//! +//! See [_features] for a list of all Cargo features and what they do. +//! +//! ### Migrating Major Versions +//! +//! See [_migrating] for a summary of how to migrate from one major version to another. +//! +//! ### Examples +//! +//! ```rust +//! use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; +//! +//! #[contract] +//! pub struct Contract; +//! +//! #[contractimpl] +//! impl Contract { +//! pub fn hello(env: Env, to: Symbol) -> Vec { +//! vec![&env, symbol_short!("Hello"), to] +//! } +//! } +//! +//! #[test] +//! fn test() { +//! # } +//! # #[cfg(feature = "testutils")] +//! # fn main() { +//! let env = Env::default(); +//! let contract_id = env.register(Contract, ()); +//! let client = ContractClient::new(&env, &contract_id); +//! +//! let words = client.hello(&symbol_short!("Dev")); +//! +//! assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); +//! } +//! # #[cfg(not(feature = "testutils"))] +//! # fn main() { } +//! ``` +//! +//! More examples are available at: +//! - +//! - + +#![cfg_attr(target_family = "wasm", no_std)] +#![cfg_attr(feature = "docs", feature(doc_cfg))] +#![allow(dead_code)] + +pub mod _features; +pub mod _migrating; + +#[cfg(all(target_family = "wasm", feature = "testutils"))] +compile_error!("'testutils' feature is not supported on 'wasm' target"); + +// When used in a no_std contract, provide a panic handler as one is required. +#[cfg(target_family = "wasm")] +#[panic_handler] +fn handle_panic(_: &core::panic::PanicInfo) -> ! { + core::arch::wasm32::unreachable() +} + +#[cfg(feature = "alloc")] +#[cfg_attr(feature = "docs", doc(cfg(feature = "alloc")))] +pub mod alloc; + +/// This const block contains link sections that need to end up in the final +/// build of any contract using the SDK. +/// +/// In Rust's build system sections only get included into the final build if +/// the object file containing those sections are processed by the linker, but +/// as an optimization step if no code is called in an object file it is +/// discarded. This has the unfortunate effect of causing anything else in +/// those object files, such as link sections, to be discarded. Placing anything +/// that must be included in the build inside an exported static or function +/// ensures the object files won't be discarded. wasm-bindgen does a similar +/// thing to this with a function, and so this seems to be a reasonably +/// accepted way to work around this limitation in the build system. The SDK +/// uses a static exported with name `_` that becomes a global because a global +/// is more unnoticeable, and takes up less bytes. +/// +/// The const block has no affect on the above problem and exists only to group +/// the static and link sections under a shared cfg. +/// +/// See https://github.com/stellar/rs-soroban-sdk/issues/383 for more details. +#[cfg(target_family = "wasm")] +const _: () = { + /// This exported static is guaranteed to end up in the final binary of any + /// importer, as a global. It exists to ensure the link sections are + /// included in the final build artifact. See notes above. + #[export_name = "_"] + static __: () = (); + + #[link_section = "contractenvmetav0"] + static __ENV_META_XDR: [u8; env::internal::meta::XDR.len()] = env::internal::meta::XDR; + + // Rustc version. + contractmeta!(key = "rsver", val = env!("RUSTC_VERSION"),); + + // Rust Soroban SDK version. Don't emit when the cfg is set. The cfg is set when building test + // wasms in this repository, so that every commit in this repo does not cause the test wasms in + // this repo to have a new hash due to the revision being embedded. The wasm hash gets embedded + // into a few places, such as test snapshots, or get used in test themselves where if they are + // constantly changing creates repetitive diffs. + #[cfg(not(soroban_sdk_internal_no_rssdkver_meta))] + contractmeta!( + key = "rssdkver", + val = concat!(env!("CARGO_PKG_VERSION"), "#", env!("GIT_REVISION")), + ); + + // An indicator of the spec shaking version in use. Signals to the stellar-cli that the .wasm + // needs to have its spec shaken. See soroban_spec::shaking for constants and version detection. + // The contractmeta! macro requires string literals, so we assert the literals match the + // constants defined in soroban_spec::shaking. + #[cfg(feature = "experimental_spec_shaking_v2")] + contractmeta!(key = "rssdk_spec_shaking", val = "2"); +}; + +// Re-exports of dependencies used by macros. +#[doc(hidden)] +pub mod reexports_for_macros { + pub use bytes_lit; + #[cfg(any(test, feature = "testutils"))] + pub use ctor; +} + +/// `debug_assert_in_contract!` asserts that the contract is currently executing within a +/// contract. The macro expands to an assertion when testutils are enabled or in tests, +/// otherwise it expands to nothing. +macro_rules! debug_assert_in_contract { + ($env:expr $(,)?) => {{ + { + #[cfg(any(test, feature = "testutils"))] + assert!( + ($env).in_contract(), + "this function is not accessible outside of a contract, wrap \ + the call with `env.as_contract()` to access it from a \ + particular contract" + ); + } + }}; +} + +// For internal use, use `debug_assert_in_contract!` instead. +/// Assert in contract asserts that the contract is currently executing within a +/// contract. The macro maps to code when testutils are enabled or in tests, +/// otherwise maps to nothing. +#[deprecated(note = "this macro is deprecated and will be removed in a future release")] +#[macro_export] +macro_rules! assert_in_contract { + ($env:expr $(,)?) => {{ + { + #[cfg(any(test, feature = "testutils"))] + assert!( + ($env).in_contract(), + "this function is not accessible outside of a contract, wrap \ + the call with `env.as_contract()` to access it from a \ + particular contract" + ); + } + }}; +} + +/// Create a short [Symbol] constant with the given string. +/// +/// A short symbol's maximum length is 9 characters. For longer symbols, use +/// [Symbol::new] to create the symbol at runtime. +/// +/// Valid characters are `a-zA-Z0-9_`. +/// +/// The [Symbol] is generated at compile time and returned as a const. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{symbol_short, Symbol}; +/// +/// let symbol = symbol_short!("a_str"); +/// assert_eq!(symbol, symbol_short!("a_str")); +/// ``` +pub use soroban_sdk_macros::symbol_short; + +/// Generates conversions from the repr(u32) enum from/into an `Error`. +/// +/// There are some constraints on the types that are supported: +/// - Enum must derive `Copy`. +/// - Enum variants must have an explicit integer literal. +/// - Enum variants must have a value convertible to u32. +/// +/// Includes the type in the contract spec so that clients can generate bindings +/// for the type. By default, spec entries are only generated for `pub` types +/// (or when `export = true` is explicitly set). +/// +/// ### `experimental_spec_shaking_v2` +/// +/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] +/// feature is enabled, spec entries are generated for all types regardless of +/// visibility, and markers are embedded that allow post-build tools to strip +/// entries for types that are not used at a contract boundary. See +/// [`_features`] for details. +/// +/// ### Examples +/// +/// Defining an error and capturing errors using the `try_` variant. +/// +/// ``` +/// use soroban_sdk::{contract, contracterror, contractimpl, Env}; +/// +/// #[contracterror] +/// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +/// #[repr(u32)] +/// pub enum Error { +/// MyError = 1, +/// AnotherError = 2, +/// } +/// +/// #[contract] +/// pub struct Contract; +/// +/// #[contractimpl] +/// impl Contract { +/// pub fn causeerror(env: Env) -> Result<(), Error> { +/// Err(Error::MyError) +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// +/// // Register the contract defined in this crate. +/// let contract_id = env.register(Contract, ()); +/// +/// // Create a client for calling the contract. +/// let client = ContractClient::new(&env, &contract_id); +/// +/// // Invoke contract causeerror function, but use the try_ variant that +/// // will capture the error so we can inspect. +/// let result = client.try_causeerror(); +/// assert_eq!(result, Err(Ok(Error::MyError))); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +/// +/// Testing invocations that cause errors with `should_panic` instead of `try_`. +/// +/// ```should_panic +/// # use soroban_sdk::{contract, contracterror, contractimpl, Env}; +/// # +/// # #[contracterror] +/// # #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +/// # #[repr(u32)] +/// # pub enum Error { +/// # MyError = 1, +/// # AnotherError = 2, +/// # } +/// # +/// # #[contract] +/// # pub struct Contract; +/// # +/// # #[contractimpl] +/// # impl Contract { +/// # pub fn causeerror(env: Env) -> Result<(), Error> { +/// # Err(Error::MyError) +/// # } +/// # } +/// # +/// #[test] +/// #[should_panic(expected = "ContractError(1)")] +/// fn test() { +/// # panic!("ContractError(1)"); +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// +/// // Register the contract defined in this crate. +/// let contract_id = env.register(Contract, ()); +/// +/// // Create a client for calling the contract. +/// let client = ContractClient::new(&env, &contract_id); +/// +/// // Invoke contract causeerror function. +/// client.causeerror(); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contracterror; + +/// Import a contract from its WASM file, generating a client, types, and +/// constant holding the contract file. +/// +/// The path given is relative to the workspace root, and not the current +/// file. +/// +/// Generates in the current module: +/// - A `Contract` trait that matches the contracts interface. +/// - A `ContractClient` struct that has functions for each function in the +/// contract. +/// - Types for all contract types defined in the contract. +/// +/// ### `experimental_spec_shaking_v2` +/// +/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] +/// feature is enabled, imported types are generated with `export = true` so +/// they produce spec entries and markers in the importing contract. Post-build +/// tools strip entries for imported types that are not used at the importing +/// contract's boundary. Without this feature, imported types use +/// `export = false` and do not produce spec entries. See [`_features`] for +/// details. +/// +/// ### SHA-256 Verification +/// +/// An optional `sha256` parameter can be provided to verify the integrity of +/// the WASM file at compile time. When provided, the macro computes the +/// SHA-256 hash of the WASM file at compile time and produces a compile error +/// if it does not match the provided value. The `sha256` argument must +/// be a hex-encoded SHA-256 digest (64 hex chars, no 0x prefix). +/// +/// ```ignore +/// mod contract_a { +/// soroban_sdk::contractimport!( +/// file = "contract_a.wasm", +/// sha256 = "d5bc0a5b4...", +/// ); +/// } +/// ``` +/// +/// ### Examples +/// +/// ```ignore +/// use soroban_sdk::{contractimpl, BytesN, Env, Symbol}; +/// +/// mod contract_a { +/// soroban_sdk::contractimport!(file = "contract_a.wasm"); +/// } +/// +/// pub struct ContractB; +/// +/// #[contractimpl] +/// impl ContractB { +/// pub fn add_with(env: Env, contract_id: BytesN<32>, x: u32, y: u32) -> u32 { +/// let client = contract_a::ContractClient::new(&env, contract_id); +/// client.add(&x, &y) +/// } +/// } +/// +/// #[test] +/// fn test() { +/// let env = Env::default(); +/// +/// // Register contract A using the imported WASM. +/// let contract_a_id = env.register_contract_wasm(None, contract_a::WASM); +/// +/// // Register contract B defined in this crate. +/// let contract_b_id = env.register(ContractB, ()); +/// +/// // Create a client for calling contract B. +/// let client = ContractBClient::new(&env, &contract_b_id); +/// +/// // Invoke contract B via its client. +/// let sum = client.add_with(&contract_a_id, &5, &7); +/// assert_eq!(sum, 12); +/// } +/// ``` +pub use soroban_sdk_macros::contractimport; + +/// Marks a type as being the type that contract functions are attached for. +/// +/// Use `#[contractimpl]` on impl blocks of this type to make those functions +/// contract functions. +/// +/// Note that a crate only ever exports a single contract. While there can be +/// multiple types in a crate with `#[contract]`, when built as a wasm file and +/// deployed the combination of all contract functions and all contracts within +/// a crate will be seen as a single contract. +/// +/// ### Examples +/// +/// Define a contract with one function, `hello`, and call it from within a test +/// using the generated client. +/// +/// ``` +/// use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; +/// +/// #[contract] +/// pub struct HelloContract; +/// +/// #[contractimpl] +/// impl HelloContract { +/// pub fn hello(env: Env, to: Symbol) -> Vec { +/// vec![&env, symbol_short!("Hello"), to] +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// let contract_id = env.register(HelloContract, ()); +/// let client = HelloContractClient::new(&env, &contract_id); +/// +/// let words = client.hello(&symbol_short!("Dev")); +/// +/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contract; + +/// Exports the publicly accessible functions to the Soroban environment. +/// +/// Functions that are publicly accessible in the implementation are invocable +/// by other contracts, or directly by transactions, when deployed. +/// +/// ### Notes +/// +/// Each public function's export name is derived from the function name alone, +/// without any type prefix or namespace. This means: +/// +/// - **Function names must be unique across all `#[contractimpl]` blocks in a +/// crate.** If two impl blocks define a function with the same name, their +/// Wasm exports will collide, producing build or linker errors. +/// +/// - **Importing a crate that contains `#[contractimpl]` blocks will pull its +/// exported functions into the importing crate's Wasm binary.** This is a +/// limitation of Rust — any `#[export_name = "..."]` function in a dependency +/// is included in the final binary. This can cause unexpected exports or name +/// collisions that are hard to diagnose. For this reason it is usually +/// inadvisable to import dependencies that use `#[contractimpl]`. +/// +/// ### Examples +/// +/// Define a contract with one function, `hello`, and call it from within a test +/// using the generated client. +/// +/// ``` +/// use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; +/// +/// #[contract] +/// pub struct HelloContract; +/// +/// #[contractimpl] +/// impl HelloContract { +/// pub fn hello(env: Env, to: Symbol) -> Vec { +/// vec![&env, symbol_short!("Hello"), to] +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// let contract_id = env.register(HelloContract, ()); +/// let client = HelloContractClient::new(&env, &contract_id); +/// +/// let words = client.hello(&symbol_short!("Dev")); +/// +/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contractimpl; + +/// Defines a contract trait with default function implementations that can be +/// used by contracts. +/// +/// The `contracttrait` macro generates a trait that contracts can implement +/// using `contractimpl`. Functions defined with default implementations in +/// the trait will be automatically exported as contract functions when a +/// contract implements the trait using `#[contractimpl(contracttrait)]`. +/// +/// This is useful for defining standard interfaces where some functions have +/// default implementations that can be optionally overridden. +/// +/// Note: The `contracttrait` macro is not required on traits, but without it +/// default functions will not be exported by contracts that implement the +/// trait. +/// +/// ### Macro Arguments +/// +/// - `crate_path` - The path to the soroban-sdk crate. Defaults to `soroban_sdk`. +/// - `spec_name` - The name for the spec type. Defaults to `{TraitName}Spec`. +/// - `spec_export` - Whether to export the spec for default functions. Defaults to `false`. +/// - `args_name` - The name for the args type. Defaults to `{TraitName}Args`. +/// - `client_name` - The name for the client type. Defaults to `{TraitName}Client`. +/// +/// ### Examples +/// +/// Define a trait with a default function and implement it in a contract: +/// +/// ``` +/// use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; +/// +/// #[contracttrait] +/// pub trait Token { +/// fn balance(env: &Env, id: Address) -> i128 { +/// // ... +/// # todo!() +/// } +/// +/// // Default function. +/// fn transfer(env: &Env, from: Address, to: Address, amount: i128) { +/// // ... +/// # todo!() +/// } +/// } +/// +/// #[contract] +/// pub struct TokenContract; +/// +/// #[contractimpl(contracttrait)] +/// impl Token for TokenContract { +/// fn balance(env: &Env, id: Address) -> i128 { +/// // Provide a custom impl of balance. +/// // ... +/// # todo!() +/// } +/// } +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contracttrait; + +/// Generates a macro for a trait that calls +/// contractimpl_trait_default_fns_not_overridden with information about the trait. +/// +/// This macro is used internally and is not intended to be used directly by contracts. +#[doc(hidden)] +pub use soroban_sdk_macros::contractimpl_trait_macro; + +/// Generates code the same as contractimpl does, but for the default functions of a trait that are +/// not overridden. +/// +/// This macro is used internally and is not intended to be used directly by contracts. +#[doc(hidden)] +pub use soroban_sdk_macros::contractimpl_trait_default_fns_not_overridden; + +/// Adds a serialized SCMetaEntry::SCMetaV0 to the WASM contracts custom section +/// under the section name 'contractmetav0'. Contract developers can use this to +/// append metadata to their contract. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{contract, contractimpl, contractmeta, vec, symbol_short, BytesN, Env, Symbol, Vec}; +/// +/// contractmeta!(key="desc", val="hello world contract"); +/// +/// #[contract] +/// pub struct HelloContract; +/// +/// #[contractimpl] +/// impl HelloContract { +/// pub fn hello(env: Env, to: Symbol) -> Vec { +/// vec![&env, symbol_short!("Hello"), to] +/// } +/// } +/// +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// let contract_id = env.register(HelloContract, ()); +/// let client = HelloContractClient::new(&env, &contract_id); +/// +/// let words = client.hello(&symbol_short!("Dev")); +/// +/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contractmeta; + +/// Generates conversions from the struct/enum from/into a `Val`. +/// +/// There are some constraints on the types that are supported: +/// - Enums with integer values must have an explicit integer literal for every +/// variant. +/// - Enums with unit variants are supported. +/// - Enums with tuple-like variants with a maximum of one tuple field are +/// supported. The tuple field must be of a type that is also convertible to and +/// from `Val`. +/// - Enums with struct-like variants are not supported. +/// - Structs are supported. All fields must be of a type that is also +/// convertible to and from `Val`. +/// - All variant names, field names, and type names must be 10-characters or +/// less in length. +/// +/// Includes the type in the contract spec so that clients can generate bindings +/// for the type. By default, spec entries are only generated for `pub` types +/// (or when `export = true` is explicitly set). +/// +/// ### `experimental_spec_shaking_v2` +/// +/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] +/// feature is enabled, spec entries are generated for all types regardless of +/// visibility, and markers are embedded that allow post-build tools to strip +/// entries for types that are not used at a contract boundary. See +/// [`_features`] for details. +/// +/// ### Examples +/// +/// Defining a contract type that is a struct and use it in a contract. +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, Env, Symbol}; +/// +/// #[contracttype] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct State { +/// pub count: u32, +/// pub last_incr: u32, +/// } +/// +/// #[contract] +/// pub struct Contract; +/// +/// #[contractimpl] +/// impl Contract { +/// /// Increment increments an internal counter, and returns the value. +/// pub fn increment(env: Env, incr: u32) -> u32 { +/// // Get the current count. +/// let mut state = Self::get_state(env.clone()); +/// +/// // Increment the count. +/// state.count += incr; +/// state.last_incr = incr; +/// +/// // Save the count. +/// env.storage().persistent().set(&symbol_short!("STATE"), &state); +/// +/// // Return the count to the caller. +/// state.count +/// } +/// +/// /// Return the current state. +/// pub fn get_state(env: Env) -> State { +/// env.storage().persistent() +/// .get(&symbol_short!("STATE")) +/// .unwrap_or_else(|| State::default()) // If no value set, assume 0. +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// let contract_id = env.register(Contract, ()); +/// let client = ContractClient::new(&env, &contract_id); +/// +/// assert_eq!(client.increment(&1), 1); +/// assert_eq!(client.increment(&10), 11); +/// assert_eq!( +/// client.get_state(), +/// State { +/// count: 11, +/// last_incr: 10, +/// }, +/// ); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +/// +/// Defining contract types that are three different types of enums and using +/// them in a contract. +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, Symbol, Env}; +/// +/// /// A tuple enum is stored as a two-element vector containing the name of +/// /// the enum variant as a Symbol, then the value in the tuple. +/// #[contracttype] +/// #[derive(Clone, Debug, Eq, PartialEq)] +/// pub enum Color { +/// Red(Intensity), +/// Blue(Shade), +/// } +/// +/// /// A unit enum is stored as a single-element vector containing the name of +/// /// the enum variant as a Symbol. +/// #[contracttype] +/// #[derive(Clone, Debug, Eq, PartialEq)] +/// pub enum Shade { +/// Light, +/// Dark, +/// } +/// +/// /// An integer enum is stored as its integer value. +/// #[contracttype] +/// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +/// #[repr(u32)] +/// pub enum Intensity { +/// Low = 1, +/// High = 2, +/// } +/// +/// #[contract] +/// pub struct Contract; +/// +/// #[contractimpl] +/// impl Contract { +/// /// Set the color. +/// pub fn set(env: Env, c: Color) { +/// env.storage().persistent().set(&symbol_short!("COLOR"), &c); +/// } +/// +/// /// Get the color. +/// pub fn get(env: Env) -> Option { +/// env.storage().persistent() +/// .get(&symbol_short!("COLOR")) +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// let contract_id = env.register(Contract, ()); +/// let client = ContractClient::new(&env, &contract_id); +/// +/// assert_eq!(client.get(), None); +/// +/// client.set(&Color::Red(Intensity::High)); +/// assert_eq!(client.get(), Some(Color::Red(Intensity::High))); +/// +/// client.set(&Color::Blue(Shade::Light)); +/// assert_eq!(client.get(), Some(Color::Blue(Shade::Light))); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contracttype; + +/// Generates conversions from the struct into a published event. +/// +/// Fields of the struct become topics and data parameters in the published event. +/// +/// Includes the event in the contract spec so that clients can generate bindings +/// for the type and downstream systems can understand the meaning of the event. +/// +/// ### `experimental_spec_shaking_v2` +/// +/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] +/// feature is enabled, markers are embedded that allow post-build tools to strip +/// spec entries for events that are never published at a contract boundary. See +/// [`_features`] for details. +/// +/// ### Examples +/// +/// #### Define an Event +/// +/// The event will have a single fixed topic matching the name of the struct in lower snake +/// case. The fixed topic will appear before any topics listed as fields. In the example +/// below, the topics for the event will be: +/// - `"my_event"` +/// - u32 value from the `my_topic` field +/// +/// The event's data will be a [`Map`], containing a key-value pair for each field with the key +/// being the name as a [`Symbol`]. In the example below, the data for the event will be: +/// - key: my_event_data => val: u32 +/// - key: more_event_data => val: u64 +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::contractevent; +/// +/// // Define the event using the `contractevent` attribute macro. +/// #[contractevent] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct MyEvent { +/// // Mark fields as topics, for the value to be included in the events topic list so +/// // that downstream systems know to index it. +/// #[topic] +/// pub my_topic: u32, +/// // Fields not marked as topics will appear in the events data section. +/// pub my_event_data: u32, +/// pub more_event_data: u64, +/// } +/// +/// # fn main() { } +/// ``` +/// +/// #### Define an Event with Custom Topics +/// +/// Define a contract event with a custom list of fixed topics. +/// +/// The fixed topics can be change to another value. In the example +/// below, the topics for the event will be: +/// - `"my_contract"` +/// - `"an_event"` +/// - u32 value from the `my_topic` field +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::contractevent; +/// +/// // Define the event using the `contractevent` attribute macro. +/// #[contractevent(topics = ["my_contract", "an_event"])] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct MyEvent { +/// // Mark fields as topics, for the value to be included in the events topic list so +/// // that downstream systems know to index it. +/// #[topic] +/// pub my_topic: u32, +/// // Fields not marked as topics will appear in the events data section. +/// pub my_event_data: u32, +/// pub more_event_data: u64, +/// } +/// +/// # fn main() { } +/// ``` +/// +/// #### Define an Event with Other Data Formats +/// +/// The data format of the event is a map by default, but can alternatively be defined as a `vec` +/// or `single-value`. +/// +/// ##### Vec +/// +/// In the example below, the data for the event will be a [`Vec`] containing: +/// - u32 +/// - u64 +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::contractevent; +/// +/// // Define the event using the `contractevent` attribute macro. +/// #[contractevent(data_format = "vec")] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct MyEvent { +/// // Mark fields as topics, for the value to be included in the events topic list so +/// // that downstream systems know to index it. +/// #[topic] +/// pub my_topic: u32, +/// // Fields not marked as topics will appear in the events data section. +/// pub my_event_data: u32, +/// pub more_event_data: u64, +/// } +/// +/// # fn main() { } +/// ``` +/// +/// ##### Single Value +/// +/// In the example below, the data for the event will be a u32. +/// +/// When the data format is a single value there must be no more than one data field. +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::contractevent; +/// +/// // Define the event using the `contractevent` attribute macro. +/// #[contractevent(data_format = "single-value")] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct MyEvent { +/// // Mark fields as topics, for the value to be included in the events topic list so +/// // that downstream systems know to index it. +/// #[topic] +/// pub my_topic: u32, +/// // Fields not marked as topics will appear in the events data section. +/// pub my_event_data: u32, +/// } +/// +/// # fn main() { } +/// ``` +/// +/// #### A Full Example +/// +/// Defining an event, publishing it in a contract, and testing it. +/// +/// ``` +/// #![no_std] +/// use soroban_sdk::{contract, contractevent, contractimpl, contracttype, symbol_short, Env, Symbol}; +/// +/// // Define the event using the `contractevent` attribute macro. +/// #[contractevent] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct Increment { +/// // Mark fields as topics, for the value to be included in the events topic list so +/// // that downstream systems know to index it. +/// #[topic] +/// pub change: u32, +/// // Fields not marked as topics will appear in the events data section. +/// pub count: u32, +/// } +/// +/// #[contracttype] +/// #[derive(Clone, Default, Debug, Eq, PartialEq)] +/// pub struct State { +/// pub count: u32, +/// pub last_incr: u32, +/// } +/// +/// #[contract] +/// pub struct Contract; +/// +/// #[contractimpl] +/// impl Contract { +/// /// Increment increments an internal counter, and returns the value. +/// /// Publishes an event about the change in the counter. +/// pub fn increment(env: Env, incr: u32) -> u32 { +/// // Get the current count. +/// let mut state = Self::get_state(env.clone()); +/// +/// // Increment the count. +/// state.count += incr; +/// state.last_incr = incr; +/// +/// // Save the count. +/// env.storage().persistent().set(&symbol_short!("STATE"), &state); +/// +/// // Publish an event about the change. +/// Increment { +/// change: incr, +/// count: state.count, +/// }.publish(&env); +/// +/// // Return the count to the caller. +/// state.count +/// } +/// +/// /// Return the current state. +/// pub fn get_state(env: Env) -> State { +/// env.storage().persistent() +/// .get(&symbol_short!("STATE")) +/// .unwrap_or_else(|| State::default()) // If no value set, assume 0. +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// let contract_id = env.register(Contract, ()); +/// let client = ContractClient::new(&env, &contract_id); +/// +/// assert_eq!(client.increment(&1), 1); +/// assert_eq!(client.increment(&10), 11); +/// assert_eq!( +/// client.get_state(), +/// State { +/// count: 11, +/// last_incr: 10, +/// }, +/// ); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +pub use soroban_sdk_macros::contractevent; + +/// Generates a type that helps build function args for a contract trait. +pub use soroban_sdk_macros::contractargs; + +/// Generates a client for a contract trait. +/// +/// Can be used to create clients for contracts that live outside the current +/// crate, using a trait that has been published as a standard or shared +/// interface. +/// +/// Primarily useful when needing to generate a client for someone elses +/// contract where they have only shared a trait interface. +/// +/// Note that [`contractimpl`] also automatically generates a client, and so it +/// is unnecessary to use [`contractclient`] for contracts that live in the +/// current crate. +/// +/// Note that [`contractimport`] also automatically generates a client when +/// importing someone elses contract where they have shared a .wasm file. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{contract, contractclient, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; +/// +/// #[contractclient(name = "Client")] +/// pub trait HelloInteface { +/// fn hello(env: Env, to: Symbol) -> Vec; +/// } +/// +/// #[contract] +/// pub struct HelloContract; +/// +/// #[contractimpl] +/// impl HelloContract { +/// pub fn hello(env: Env, to: Symbol) -> Vec { +/// vec![&env, symbol_short!("Hello"), to] +/// } +/// } +/// +/// #[test] +/// fn test() { +/// # } +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// let env = Env::default(); +/// +/// // Register the hello contract. +/// let contract_id = env.register(HelloContract, ()); +/// +/// // Create a client for the hello contract, that was constructed using +/// // the trait. +/// let client = Client::new(&env, &contract_id); +/// +/// let words = client.hello(&symbol_short!("Dev")); +/// +/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); +/// } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +pub use soroban_sdk_macros::contractclient; + +/// Generates a contract spec for a trait or impl. +/// +/// Note that [`contractimpl`] also generates a contract spec and it is in most +/// cases not necessary to use this macro. +#[doc(hidden)] +pub use soroban_sdk_macros::contractspecfn; + +/// Import a contract from its WASM file, generating a constant holding the +/// contract file. +/// +/// Note that [`contractimport`] also automatically imports the contract file +/// into a constant, and so it is usually unnecessary to use [`contractfile`] +/// directly, unless you specifically want to only load the contract file +/// without generating a client for it. +/// +/// ### SHA-256 Verification +/// +/// Unlike [`contractimport`], `contractfile` **requires** a `sha256` +/// parameter. The macro computes the SHA-256 hash of the WASM file at compile +/// time and produces a compile error if it does not match the provided value. +/// The `sha256` argument must be a hex-encoded SHA-256 digest (64 hex chars, no 0x prefix). +/// +/// ```ignore +/// soroban_sdk::contractfile!( +/// file = "contract_a.wasm", +/// sha256 = "d5bc0a5b4...", +/// ); +/// ``` +pub use soroban_sdk_macros::contractfile; + +/// Panic with the given error. +/// +/// The first argument in the list must be a reference to an [Env]. +/// +/// The second argument is an error value. The error value will be given to any +/// calling contract. +/// +/// Equivalent to `panic!`, but with an error value instead of a string. The +/// error value will be given to any calling contract. +/// +/// See [`contracterror`] for how to define an error type. +#[macro_export] +macro_rules! panic_with_error { + ($env:expr, $error:expr) => {{ + $env.panic_with_error($error); + }}; +} + +#[doc(hidden)] +#[deprecated(note = "use panic_with_error!")] +#[macro_export] +macro_rules! panic_error { + ($env:expr, $error:expr) => {{ + $crate::panic_with_error!($env, $error); + }}; +} + +/// An internal panic! variant that avoids including the string +/// when building for wasm (since it's just pointless baggage). +#[cfg(target_family = "wasm")] +macro_rules! sdk_panic { + ($_msg:literal) => { + panic!() + }; + () => { + panic!() + }; +} +#[cfg(not(target_family = "wasm"))] +macro_rules! sdk_panic { + ($msg:literal) => { + panic!($msg) + }; + () => { + panic!() + }; +} + +/// Assert a condition and panic with the given error if it is false. +/// +/// The first argument in the list must be a reference to an [Env]. +/// +/// The second argument is an expression that if resolves to `false` will cause +/// a panic with the error in the third argument. +/// +/// The third argument is an error value. The error value will be given to any +/// calling contract. +/// +/// Equivalent to `assert!`, but with an error value instead of a string. The +/// error value will be given to any calling contract. +/// +/// See [`contracterror`] for how to define an error type. +#[macro_export] +macro_rules! assert_with_error { + ($env:expr, $cond:expr, $error:expr) => {{ + if !($cond) { + $crate::panic_with_error!($env, $error); + } + }}; +} + +#[doc(hidden)] +pub mod unwrap; + +mod env; + +mod address; +pub mod address_payload; +mod muxed_address; +mod symbol; + +pub use env::{ConversionError, Env}; + +/// Raw value of the Soroban smart contract platform that types can be converted +/// to and from for storing, or passing between contracts. +/// +pub use env::Val; + +/// Used to do conversions between values in the Soroban environment. +pub use env::FromVal; +/// Used to do conversions between values in the Soroban environment. +pub use env::IntoVal; +/// Used to do conversions between values in the Soroban environment. +pub use env::TryFromVal; +/// Used to do conversions between values in the Soroban environment. +pub use env::TryIntoVal; + +// Used by generated code only. +#[doc(hidden)] +pub use env::EnvBase; +#[doc(hidden)] +pub use env::Error; +#[doc(hidden)] +pub use env::MapObject; +#[doc(hidden)] +pub use env::SymbolStr; +#[doc(hidden)] +pub use env::VecObject; + +mod try_from_val_for_contract_fn; +#[doc(hidden)] +#[allow(deprecated)] +pub use try_from_val_for_contract_fn::TryFromValForContractFn; + +mod into_val_for_contract_fn; +#[doc(hidden)] +#[allow(deprecated)] +pub use into_val_for_contract_fn::IntoValForContractFn; + +#[cfg(feature = "experimental_spec_shaking_v2")] +mod spec_shaking; +#[cfg(feature = "experimental_spec_shaking_v2")] +#[doc(hidden)] +pub use spec_shaking::SpecShakingMarker; + +#[doc(hidden)] +#[deprecated(note = "use storage")] +pub mod data { + #[doc(hidden)] + #[deprecated(note = "use storage::Storage")] + pub use super::storage::Storage as Data; +} +pub mod auth; +#[macro_use] +mod bytes; +pub mod crypto; +pub mod deploy; +mod error; +pub use error::InvokeError; +pub mod events; +pub use events::{Event, Topics}; +pub mod iter; +pub mod ledger; +pub mod logs; +mod map; +pub mod prng; +pub mod storage; +pub mod token; +mod vec; +pub use address::{Address, Executable}; +pub use bytes::{Bytes, BytesN}; +pub use map::Map; +pub use muxed_address::MuxedAddress; +pub use symbol::Symbol; +pub use vec::Vec; +mod num; +pub use num::{Duration, Timepoint, I256, U256}; +mod string; +pub use string::String; +mod tuple; + +mod constructor_args; +pub use constructor_args::ConstructorArgs; + +pub mod xdr; + +pub mod testutils; + +mod arbitrary_extra; + +mod tests; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/logs.rs b/temp_sdk/soroban-sdk-26.0.1/src/logs.rs new file mode 100644 index 0000000..34a6542 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/logs.rs @@ -0,0 +1,170 @@ +//! Logging contains types for logging debug events. +//! +//! See [`log`][crate::log] for how to conveniently log debug events. +use core::fmt::Debug; + +use crate::{env::internal::EnvBase, Env, Val}; + +/// Log a debug event. +/// +/// Takes a [Env], a literal string, and an optional trailing sequence of +/// arguments that may be any value that are convertible to [`Val`]. The +/// string and arguments are appended as-is to the log, as the body of a +/// structured diagnostic event. Such events may be emitted from the host as +/// auxiliary diagnostic XDR, or converted to strings later for debugging. +/// +/// `log!` statements are only enabled in non optimized builds that have +/// `debug-assertions` enabled. To enable `debug-assertions` add the following +/// lines to `Cargo.toml`, then build with the profile specified, `--profile +/// release-with-logs`. See the cargo docs for how to use [custom profiles]. +/// +/// ```toml +/// [profile.release-with-logs] +/// inherits = "release" +/// debug-assertions = true +/// ``` +/// +/// [custom profiles]: +/// https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles +/// +/// ### Examples +/// +/// Log a string: +/// +/// ``` +/// use soroban_sdk::{log, Env}; +/// +/// let env = Env::default(); +/// +/// log!(&env, "a log entry"); +/// ``` +/// +/// Log a string with values: +/// +/// ``` +/// use soroban_sdk::{log, symbol_short, Symbol, Env}; +/// +/// let env = Env::default(); +/// +/// let value = 5; +/// log!(&env, "a log entry", value, symbol_short!("another")); +/// ``` +/// +/// Assert on logs in tests: +/// +/// ``` +/// # #[cfg(feature = "testutils")] +/// # { +/// use soroban_sdk::{log, symbol_short, Symbol, Env}; +/// +/// let env = Env::default(); +/// +/// let value = 5; +/// log!(&env, "a log entry", value, symbol_short!("another")); +/// +/// use soroban_sdk::testutils::Logs; +/// let logentry = env.logs().all().last().unwrap().clone(); +/// assert!(logentry.contains("[\"a log entry\", 5, another]")); +/// # } +/// ``` +#[macro_export] +macro_rules! log { + ($env:expr, $fmt:literal $(,)?) => { + if cfg!(debug_assertions) { + $env.logs().add($fmt, &[]); + } + }; + ($env:expr, $fmt:literal, $($args:expr),* $(,)?) => { + if cfg!(debug_assertions) { + $env.logs().add($fmt, &[ + $( + <_ as $crate::IntoVal>::into_val(&$args, $env) + ),* + ]); + } + }; +} + +/// Logs logs debug events. +/// +/// See [`log`][crate::log] for how to conveniently log debug events. +#[derive(Clone)] +pub struct Logs(Env); + +impl Debug for Logs { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Logs") + } +} + +impl Logs { + #[inline(always)] + pub(crate) fn env(&self) -> &Env { + &self.0 + } + + #[inline(always)] + pub(crate) fn new(env: &Env) -> Logs { + Logs(env.clone()) + } + + #[deprecated(note = "use [Logs::add]")] + #[inline(always)] + pub fn log(&self, msg: &'static str, args: &[Val]) { + self.add(msg, args); + } + + /// Log a debug event. + /// + /// Takes a literal string and a sequence of trailing values to add + /// as a log entry in the diagnostic event stream. + /// + /// See [`log`][crate::log] for how to conveniently log debug events. + #[inline(always)] + pub fn add(&self, msg: &'static str, args: &[Val]) { + if cfg!(debug_assertions) { + let env = self.env(); + env.log_from_slice(msg, args).unwrap(); + + #[cfg(any(test, feature = "testutils"))] + { + use crate::testutils::Logs; + std::println!("{}", self.all().last().unwrap()); + } + } + } +} + +#[cfg(any(test, feature = "testutils"))] +use crate::testutils; + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl testutils::Logs for Logs { + fn all(&self) -> std::vec::Vec { + use crate::xdr::{ + ContractEventBody, ContractEventType, ScSymbol, ScVal, ScVec, StringM, VecM, + }; + let env = self.env(); + let log_sym = ScSymbol(StringM::try_from("log").unwrap()); + let log_topics = ScVec(VecM::try_from(vec![ScVal::Symbol(log_sym)]).unwrap()); + env.host() + .get_diagnostic_events() + .unwrap() + .0 + .into_iter() + .filter_map(|e| match (&e.event.type_, &e.event.body) { + (ContractEventType::Diagnostic, ContractEventBody::V0(ce)) + if &ce.topics == &log_topics.0 => + { + Some(format!("{}", &e)) + } + _ => None, + }) + .collect::>() + } + + fn print(&self) { + std::println!("{}", self.all().join("\n")) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/map.rs b/temp_sdk/soroban-sdk-26.0.1/src/map.rs new file mode 100644 index 0000000..45f9e88 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/map.rs @@ -0,0 +1,1169 @@ +use core::{ + cmp::Ordering, convert::Infallible, fmt::Debug, iter::FusedIterator, marker::PhantomData, +}; + +use crate::{ + iter::{UnwrappedEnumerable, UnwrappedIter}, + unwrap::{UnwrapInfallible, UnwrapOptimized}, +}; + +use super::{ + env::internal::{Env as _, MapObject, U32Val}, + ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, Vec, +}; + +#[cfg(not(target_family = "wasm"))] +use super::xdr::ScVal; + +#[cfg(doc)] +use crate::storage::Storage; + +/// Create a [Map] with the given key-value pairs. +/// +/// The first argument in the list must be a reference to an [Env], then the +/// key-value pairs follow in a tuple `(key, value)`. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{Env, Map, map}; +/// +/// let env = Env::default(); +/// let map = map![&env, (1, 10), (2, 20)]; +/// assert_eq!(map.len(), 2); +/// ``` +#[macro_export] +macro_rules! map { + ($env:expr $(,)?) => { + $crate::Map::new($env) + }; + ($env:expr, $(($k:expr, $v:expr $(,)?)),+ $(,)?) => { + $crate::Map::from_array($env, [$(($k, $v)),+]) + }; +} + +/// Map is a ordered key-value dictionary. +/// +/// The map is ordered by its keys. Iterating a map is stable and always returns +/// the keys and values in order of the keys. +/// +/// The map is stored in the Host and available to the Guest through the +/// functions defined on Map. Values stored in the Map are transmitted to the +/// Host as [Val]s, and when retrieved from the Map are transmitted back and +/// converted from [Val] back into their type. +/// +/// The pairs of keys and values in a Map are not guaranteed to be of type +/// `K`/`V` and conversion will fail if they are not. Most functions on Map have +/// a try_ variation that returns a Result that will be Err if the conversion fails. +/// Functions that are not prefixed with try_ will panic if conversion fails." +/// +/// There are some cases where this lack of guarantee is important: +/// +/// - When storing a Map that has been provided externally as a contract +/// function argument, be aware there is no guarantee that all pairs in the Map +/// will be of type `K` and `V`. It may be necessary to validate all pairs, +/// either before storing, or when loading with `try_` variation functions. +/// +/// - When accessing and iterating over a Map that has been provided externally +/// as a contract function input, and the contract needs to be resilient to +/// failure, use the `try_` variation functions. +/// +/// Maps have at most one entry per key. Setting a value for a key in the map +/// that already has a value for that key replaces the value. +/// +/// Map values can be stored as [Storage], or in other types like [Vec], [Map], +/// etc. +/// +/// ### Examples +/// +/// Maps can be created and iterated. +/// +/// ``` +/// use soroban_sdk::{Env, Map, map}; +/// +/// let env = Env::default(); +/// let map = map![&env, (2, 20), (1, 10)]; +/// assert_eq!(map.len(), 2); +/// assert_eq!(map.iter().next(), Some((1, 10))); +/// ``` +/// +/// Maps are ordered and so maps created with elements in different order will +/// be equal. +/// +/// ``` +/// use soroban_sdk::{Env, Map, map}; +/// +/// let env = Env::default(); +/// assert_eq!( +/// map![&env, (1, 10), (2, 20)], +/// map![&env, (2, 20), (1, 10)], +/// ) +/// ``` +#[derive(Clone)] +pub struct Map { + env: Env, + obj: MapObject, + _k: PhantomData, + _v: PhantomData, +} + +impl Eq for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ +} + +impl PartialEq for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + #[cfg(not(target_family = "wasm"))] + if !self.env.is_same_env(&other.env) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = self + .env + .obj_cmp(self.obj.to_val(), other.obj.to_val()) + .unwrap_infallible(); + v.cmp(&0) + } +} + +impl Debug for Map +where + K: IntoVal + TryFromVal + Debug + Clone, + K::Error: Debug, + V: IntoVal + TryFromVal + Debug + Clone, + V::Error: Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Map(")?; + let mut iter = self.try_iter(); + if let Some(x) = iter.next() { + write!(f, "{:?}", x)?; + } + for x in iter { + write!(f, ", {:?}", x)?; + } + write!(f, ")")?; + Ok(()) + } +} + +impl TryFromVal for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Error = Infallible; + + #[inline(always)] + fn try_from_val(env: &Env, obj: &MapObject) -> Result { + Ok(Map { + env: env.clone(), + obj: *obj, + _k: PhantomData, + _v: PhantomData, + }) + } +} + +impl TryFromVal for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(MapObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl TryFromVal> for Val +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Error = Infallible; + + fn try_from_val(_env: &Env, v: &Map) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal> for Val +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Error = Infallible; + + fn try_from_val(_env: &Env, v: &&Map) -> Result { + Ok(v.to_val()) + } +} + +impl From> for Val +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + #[inline(always)] + fn from(m: Map) -> Self { + m.obj.into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Map> for ScVal { + fn from(v: &Map) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From> for ScVal { + fn from(v: Map) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal> for ScVal { + type Error = ConversionError; + fn try_from_val(_e: &Env, v: &Map) -> Result { + Ok(v.into()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok(MapObject::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl Map { + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: MapObject) -> Self { + Self { + env, + obj, + _k: PhantomData, + _v: PhantomData, + } + } + + #[inline(always)] + pub fn env(&self) -> &Env { + &self.env + } + + #[inline(always)] + pub fn as_val(&self) -> &Val { + self.obj.as_val() + } + + #[inline(always)] + pub fn to_val(&self) -> Val { + self.obj.to_val() + } + + #[inline(always)] + pub(crate) fn as_object(&self) -> &MapObject { + &self.obj + } + + #[inline(always)] + pub(crate) fn to_object(&self) -> MapObject { + self.obj + } +} + +impl Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + /// Create an empty Map. + #[inline(always)] + pub fn new(env: &Env) -> Map { + unsafe { Self::unchecked_new(env.clone(), env.map_new().unwrap_infallible()) } + } + + /// Create a Map from the key-value pairs in the array. + #[inline(always)] + pub fn from_array(env: &Env, items: [(K, V); N]) -> Map { + let mut map = Map::::new(env); + for (k, v) in items { + map.set(k, v); + } + map + } + + /// Returns true if a key-value pair exists in the map with the given key. + #[inline(always)] + pub fn contains_key(&self, k: K) -> bool { + self.env + .map_has(self.obj, k.into_val(&self.env)) + .unwrap_infallible() + .into() + } + + /// Returns the value corresponding to the key or None if the map does not + /// contain a value with the specified key. + /// + /// ### Panics + /// + /// If the value corresponding to the key cannot be converted to type V. + #[inline(always)] + pub fn get(&self, k: K) -> Option { + self.try_get(k).unwrap_optimized() + } + + /// Returns the value corresponding to the key or None if the map does not + /// contain a value with the specified key. + /// + /// ### Errors + /// + /// If the value corresponding to the key cannot be converted to type V. + #[inline(always)] + pub fn try_get(&self, k: K) -> Result, V::Error> { + let env = self.env(); + let k = k.into_val(env); + let has = env.map_has(self.obj, k).unwrap_infallible().into(); + if has { + let v = env.map_get(self.obj, k).unwrap_infallible(); + V::try_from_val(env, &v).map(|val| Some(val)) + } else { + Ok(None) + } + } + + /// Returns the value corresponding to the key. + /// + /// ### Panics + /// + /// If the map does not contain a value with the specified key. + /// + /// If the value corresponding to the key cannot be converted to type V. + #[inline(always)] + pub fn get_unchecked(&self, k: K) -> V { + self.try_get_unchecked(k).unwrap_optimized() + } + + /// Returns the value corresponding to the key. + /// + /// ### Errors + /// + /// If the value corresponding to the key cannot be converted to type V. + /// + /// ### Panics + /// + /// If the map does not contain a value with the specified key. + #[inline(always)] + pub fn try_get_unchecked(&self, k: K) -> Result { + let env = self.env(); + let v = env.map_get(self.obj, k.into_val(env)).unwrap_infallible(); + V::try_from_val(env, &v) + } + + /// Set the value for the specified key. + /// + /// If the map contains a value corresponding to the key, the value is + /// replaced with the given value. + #[inline(always)] + pub fn set(&mut self, k: K, v: V) { + let env = self.env(); + self.obj = env + .map_put(self.obj, k.into_val(env), v.into_val(env)) + .unwrap_infallible(); + } + + /// Remove the value corresponding to the key. + /// + /// Returns `None` if the map does not contain a value with the specified + /// key. + #[inline(always)] + pub fn remove(&mut self, k: K) -> Option<()> { + let env = self.env(); + let k = k.into_val(env); + let has = env.map_has(self.obj, k).unwrap_infallible().into(); + if has { + self.obj = env.map_del(self.obj, k).unwrap_infallible(); + Some(()) + } else { + None + } + } + + /// Remove the value corresponding to the key. + /// + /// ### Panics + /// + /// If the map does not contain a value with the specified key. + #[inline(always)] + pub fn remove_unchecked(&mut self, k: K) { + let env = self.env(); + self.obj = env.map_del(self.obj, k.into_val(env)).unwrap_infallible(); + } + + /// Returns a [Vec] of all keys in the map, ordered in the map's key-sorted order. + /// + /// This method does not validate that the keys in the map are of type `K`. Since [Map] + /// keys are not guaranteed to be of type `K`, it is not guaranteed that all values + /// in the returned [Vec] will be of type `K`. + #[inline(always)] + pub fn keys(&self) -> Vec { + let env = self.env(); + let vec = env.map_keys(self.obj).unwrap_infallible(); + Vec::::try_from_val(env, &vec).unwrap() + } + + /// Returns a [Vec] of all values in the map, ordered in the map's key-sorted order. + /// + /// This method does not validate that the values in the map are of type `V`. Since [Map] + /// values are not guaranteed to be of type `V`, it is not guaranteed that all values + /// in the returned [Vec] will be of type `V`. + #[inline(always)] + pub fn values(&self) -> Vec { + let env = self.env(); + let vec = env.map_values(self.obj).unwrap_infallible(); + Vec::::try_from_val(env, &vec).unwrap() + } +} + +impl Map { + /// Returns true if the map is empty and contains no key-values. + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of key-value pairs in the map. + #[inline(always)] + pub fn len(&self) -> u32 { + self.env().map_len(self.obj).unwrap_infallible().into() + } +} + +impl IntoIterator for Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Item = (K, V); + type IntoIter = UnwrappedIter, (K, V), ConversionError>; + + #[inline(always)] + fn into_iter(self) -> Self::IntoIter { + MapTryIter::new(self).unwrapped() + } +} + +impl Map +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + /// Returns an iterator over the key-value pairs of the map. + /// + /// Each entry is converted from [Val] to `(K, V)` as it is yielded. + /// + /// ### Panics + /// + /// If any key or value cannot be converted to its declared type. + /// Use [`try_iter`](Map::try_iter) to handle conversion errors. + #[inline(always)] + pub fn iter(&self) -> UnwrappedIter, (K, V), ConversionError> + where + K: Clone, + V: Clone, + { + self.clone().into_iter() + } + + /// Returns an iterator over the key-value pairs of the map, yielding + /// `Result<(K, V), ConversionError>` for each entry. + #[inline(always)] + pub fn try_iter(&self) -> MapTryIter + where + K: IntoVal + TryFromVal + Clone, + V: IntoVal + TryFromVal + Clone, + { + MapTryIter::new(self.clone()) + } + + #[inline(always)] + pub fn into_try_iter(self) -> MapTryIter + where + K: IntoVal + TryFromVal + Clone, + V: IntoVal + TryFromVal + Clone, + { + MapTryIter::new(self) + } +} + +#[derive(Clone)] +pub struct MapTryIter { + map: Map, + begin: u32, + end: u32, +} + +impl MapTryIter { + fn new(map: Map) -> Self { + Self { + begin: 0, + end: map.len(), + map, + } + } +} + +impl Iterator for MapTryIter +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + type Item = Result<(K, V), ConversionError>; + + fn next(&mut self) -> Option { + let env = self.map.env(); + if self.begin >= self.end { + return None; + } + let map_obj = self.map.to_object(); + let index_val: U32Val = self.begin.into(); + let key = env.map_key_by_pos(map_obj, index_val).unwrap_infallible(); + let value = env.map_val_by_pos(map_obj, index_val).unwrap_infallible(); + self.begin += 1; + + Some(Ok(( + match K::try_from_val(env, &key) { + Ok(k) => k, + Err(_) => return Some(Err(ConversionError)), + }, + match V::try_from_val(env, &value) { + Ok(v) => v, + Err(_) => return Some(Err(ConversionError)), + }, + ))) + } + + fn size_hint(&self) -> (usize, Option) { + let len = (self.end - self.begin) as usize; + (len, Some(len)) + } + + // TODO: Implement other functions as optimizations. +} + +impl DoubleEndedIterator for MapTryIter +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + fn next_back(&mut self) -> Option { + let env = self.map.env(); + if self.begin >= self.end { + return None; + } + self.end -= 1; + let map_obj = self.map.to_object(); + let index_val: U32Val = self.end.into(); + let key = env.map_key_by_pos(map_obj, index_val).unwrap_infallible(); + let value = env.map_val_by_pos(map_obj, index_val).unwrap_infallible(); + + Some(Ok(( + match K::try_from_val(env, &key) { + Ok(k) => k, + Err(_) => return Some(Err(ConversionError)), + }, + match V::try_from_val(env, &value) { + Ok(v) => v, + Err(_) => return Some(Err(ConversionError)), + }, + ))) + } + + // TODO: Implement other functions as optimizations. +} + +impl FusedIterator for MapTryIter +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ +} + +impl ExactSizeIterator for MapTryIter +where + K: IntoVal + TryFromVal, + V: IntoVal + TryFromVal, +{ + fn len(&self) -> usize { + (self.end - self.begin) as usize + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::vec; + + #[test] + fn test_map_macro() { + let env = Env::default(); + assert_eq!(map![&env], Map::::new(&env)); + assert_eq!(map![&env, (1, 10)], { + let mut v = Map::new(&env); + v.set(1, 10); + v + }); + assert_eq!(map![&env, (1, 10),], { + let mut v = Map::new(&env); + v.set(1, 10); + v + }); + assert_eq!(map![&env, (3, 30), (2, 20), (1, 10),], { + let mut v = Map::new(&env); + v.set(3, 30); + v.set(2, 20); + v.set(1, 10); + v + }); + assert_eq!(map![&env, (3, 30,), (2, 20,), (1, 10,),], { + let mut v = Map::new(&env); + v.set(3, 30); + v.set(2, 20); + v.set(1, 10); + v + }); + } + + #[test] + fn test_empty() { + let env = Env::default(); + + let map: Map<(), ()> = map![&env]; + assert_eq!(map.len(), 0); + } + + #[test] + fn test_map_to_val() { + let env = Env::default(); + + let map = Map::::from_array(&env, [(0, ()), (1, ()), (2, ()), (3, ())]); + let val: Val = map.clone().into_val(&env); + let rt: Map = val.into_val(&env); + + assert_eq!(map, rt); + } + + #[test] + fn test_ref_map_to_val() { + let env = Env::default(); + + let map = Map::::from_array(&env, [(0, ()), (1, ()), (2, ()), (3, ())]); + let val: Val = (&map).into_val(&env); + let rt: Map = val.into_val(&env); + + assert_eq!(map, rt); + } + + #[test] + fn test_double_ref_map_to_val() { + let env = Env::default(); + + let map = Map::::from_array(&env, [(0, ()), (1, ()), (2, ()), (3, ())]); + let val: Val = (&&map).into_val(&env); + let rt: Map = val.into_val(&env); + + assert_eq!(map, rt); + } + + #[test] + fn test_raw_vals() { + let env = Env::default(); + + let map: Map = map![&env, (1, true), (2, false)]; + assert_eq!(map.len(), 2); + assert_eq!(map.get(1), Some(true)); + assert_eq!(map.get(2), Some(false)); + assert_eq!(map.get(3), None); + } + + #[test] + fn test_iter() { + let env = Env::default(); + + let map: Map<(), ()> = map![&env]; + let mut iter = map.iter(); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + + let mut iter = map.iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some((0, 0))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next(), Some((1, 10))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next(), Some((2, 20))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some((3, 30))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some((4, 40))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut iter = map.iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some((0, 0))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next_back(), Some((4, 40))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next_back(), Some((3, 30))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some((1, 10))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some((2, 20))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + + let mut iter = map.iter().rev(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some((4, 40))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next_back(), Some((0, 0))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next_back(), Some((1, 10))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some((3, 30))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some((2, 20))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + } + + #[test] + #[should_panic(expected = "ConversionError")] + fn test_iter_panic_on_key_conversion() { + let env = Env::default(); + + let map: Map = map![&env, (1i64.into_val(&env), 2i32.into_val(&env)),]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + + let mut iter = map.iter(); + iter.next(); + } + + #[test] + #[should_panic(expected = "ConversionError")] + fn test_iter_panic_on_value_conversion() { + let env = Env::default(); + + let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env)),]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + + let mut iter = map.iter(); + iter.next(); + } + + #[test] + fn test_try_iter() { + let env = Env::default(); + + let map: Map<(), ()> = map![&env]; + let mut iter = map.iter(); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + + let mut iter = map.try_iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(Ok((0, 0)))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next(), Some(Ok((1, 10)))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next(), Some(Ok((2, 20)))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(Ok((3, 30)))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(Ok((4, 40)))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut iter = map.try_iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(Ok((0, 0)))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next_back(), Some(Ok((4, 40)))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next_back(), Some(Ok((3, 30)))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(Ok((1, 10)))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(Ok((2, 20)))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + + let mut iter = map.try_iter().rev(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(Ok((4, 40)))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next_back(), Some(Ok((0, 0)))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next_back(), Some(Ok((1, 10)))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(Ok((3, 30)))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(Ok((2, 20)))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + } + + #[test] + fn test_iter_error_on_key_conversion() { + let env = Env::default(); + + let map: Map = map![ + &env, + (1i32.into_val(&env), 2i32.into_val(&env)), + (3i64.into_val(&env), 4i32.into_val(&env)), + ]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + + let mut iter = map.try_iter(); + assert_eq!(iter.next(), Some(Ok((1, 2)))); + assert_eq!(iter.next(), Some(Err(ConversionError))); + } + + #[test] + fn test_iter_error_on_value_conversion() { + let env = Env::default(); + + let map: Map = map![ + &env, + (1i32.into_val(&env), 2i32.into_val(&env)), + (3i32.into_val(&env), 4i64.into_val(&env)), + ]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + + let mut iter = map.try_iter(); + assert_eq!(iter.next(), Some(Ok((1, 2)))); + assert_eq!(iter.next(), Some(Err(ConversionError))); + } + + #[test] + fn test_keys() { + let env = Env::default(); + + let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + let keys = map.keys(); + assert_eq!(keys, vec![&env, 0, 1, 2, 3, 4]); + } + + #[test] + fn test_values() { + let env = Env::default(); + + let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + let values = map.values(); + assert_eq!(values, vec![&env, 0, 10, 20, 30, 40]); + } + + #[test] + fn test_from_array() { + let env = Env::default(); + + let map = Map::from_array(&env, [(0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]); + assert_eq!(map, map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]); + + let map: Map = Map::from_array(&env, []); + assert_eq!(map, map![&env]); + } + + #[test] + fn test_contains_key() { + let env = Env::default(); + + let map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + + // contains all assigned keys + for i in 0..map.len() { + assert_eq!(true, map.contains_key(i)); + } + + // does not contain keys outside range + assert_eq!(map.contains_key(6), false); + assert_eq!(map.contains_key(u32::MAX), false); + assert_eq!(map.contains_key(8), false); + } + + #[test] + fn test_is_empty() { + let env = Env::default(); + + let mut map: Map = Map::new(&env); + assert_eq!(map.is_empty(), true); + map.set(0, 0); + assert_eq!(map.is_empty(), false); + } + + #[test] + fn test_get() { + let env = Env::default(); + + let map: Map = map![&env, (0, 0), (1, 10)]; + assert_eq!(map.get(0), Some(0)); + assert_eq!(map.get(1), Some(10)); + assert_eq!(map.get(2), None); + } + + #[test] + fn test_get_none_on_key_type_mismatch() { + let env = Env::default(); + + let map: Map = map![ + &env, + (1i32.into_val(&env), 2i32.into_val(&env)), + (3i64.into_val(&env), 4i32.into_val(&env)), + ]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + assert_eq!(map.get(1), Some(2)); + assert_eq!(map.get(3), None); + } + + #[test] + #[should_panic(expected = "ConversionError")] + fn test_get_panics_on_value_conversion() { + let env = Env::default(); + + let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env)),]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + let _ = map.get(1); + } + + #[test] + fn test_try_get() { + let env = Env::default(); + + let map: Map = map![&env, (0, 0), (1, 10)]; + assert_eq!(map.try_get(0), Ok(Some(0))); + assert_eq!(map.try_get(1), Ok(Some(10))); + assert_eq!(map.try_get(2), Ok(None)); + } + + #[test] + fn test_try_get_none_on_key_type_mismatch() { + let env = Env::default(); + + let map: Map = map![ + &env, + (1i32.into_val(&env), 2i32.into_val(&env)), + (3i64.into_val(&env), 4i32.into_val(&env)), + ]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + assert_eq!(map.try_get(1), Ok(Some(2))); + assert_eq!(map.try_get(3), Ok(None)); + } + + #[test] + fn test_try_get_errors_on_value_conversion() { + let env = Env::default(); + + let map: Map = map![ + &env, + (1i32.into_val(&env), 2i32.into_val(&env)), + (3i32.into_val(&env), 4i64.into_val(&env)), + ]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + assert_eq!(map.try_get(1), Ok(Some(2))); + assert_eq!(map.try_get(3), Err(ConversionError)); + } + + #[test] + fn test_get_unchecked() { + let env = Env::default(); + + let map: Map = map![&env, (0, 0), (1, 10)]; + assert_eq!(map.get_unchecked(0), 0); + assert_eq!(map.get_unchecked(1), 10); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, MissingValue)")] + fn test_get_unchecked_panics_on_key_type_mismatch() { + let env = Env::default(); + + let map: Map = map![&env, (1i64.into_val(&env), 2i32.into_val(&env)),]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + let _ = map.get_unchecked(1); + } + + #[test] + #[should_panic(expected = "ConversionError")] + fn test_get_unchecked_panics_on_value_conversion() { + let env = Env::default(); + + let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env)),]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + let _ = map.get_unchecked(1); + } + + #[test] + fn test_try_get_unchecked() { + let env = Env::default(); + + let map: Map = map![&env, (0, 0), (1, 10)]; + assert_eq!(map.get_unchecked(0), 0); + assert_eq!(map.get_unchecked(1), 10); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, MissingValue)")] + fn test_try_get_unchecked_panics_on_key_type_mismatch() { + let env = Env::default(); + + let map: Map = map![&env, (1i64.into_val(&env), 2i32.into_val(&env)),]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + let _ = map.try_get_unchecked(1); + } + + #[test] + fn test_try_get_unchecked_errors_on_value_conversion() { + let env = Env::default(); + + let map: Map = map![ + &env, + (1i32.into_val(&env), 2i32.into_val(&env)), + (3i32.into_val(&env), 4i64.into_val(&env)), + ]; + let map: Val = map.into(); + let map: Map = map.try_into_val(&env).unwrap(); + assert_eq!(map.try_get_unchecked(1), Ok(2)); + assert_eq!(map.try_get_unchecked(3), Err(ConversionError)); + } + + #[test] + fn test_remove() { + let env = Env::default(); + + let mut map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + + assert_eq!(map.len(), 5); + assert_eq!(map.get(2), Some(20)); + assert_eq!(map.remove(2), Some(())); + assert_eq!(map.get(2), None); + assert_eq!(map.len(), 4); + + // remove all items + map.remove(0); + map.remove(1); + map.remove(3); + map.remove(4); + assert_eq!(map![&env], map); + + // removing from empty map + let mut map: Map = map![&env]; + assert_eq!(map.remove(0), None); + assert_eq!(map.remove(u32::MAX), None); + } + + #[test] + fn test_remove_unchecked() { + let env = Env::default(); + + let mut map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + + assert_eq!(map.len(), 5); + assert_eq!(map.get(2), Some(20)); + map.remove_unchecked(2); + assert_eq!(map.get(2), None); + assert_eq!(map.len(), 4); + + // remove all items + map.remove_unchecked(0); + map.remove_unchecked(1); + map.remove_unchecked(3); + map.remove_unchecked(4); + assert_eq!(map![&env], map); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, MissingValue)")] + fn test_remove_unchecked_panic() { + let env = Env::default(); + let mut map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; + map.remove_unchecked(100); // key does not exist + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs b/temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs new file mode 100644 index 0000000..b858a31 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs @@ -0,0 +1,416 @@ +use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; + +use super::{ + env::internal::{AddressObject, Env as _, MuxedAddressObject, Tag}, + ConversionError, Env, TryFromVal, TryIntoVal, Val, +}; +use crate::{ + env::internal, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Address, Bytes, String, +}; + +#[cfg(not(target_family = "wasm"))] +use crate::env::internal::xdr::{ScAddress, ScVal}; + +#[derive(Clone)] +enum AddressObjectWrapper { + Address(AddressObject), + MuxedAddress(MuxedAddressObject), +} + +/// MuxedAddress is a union type that represents either the regular `Address`, +/// or a 'multiplexed' address that consists of a regular address and a u64 id +/// and can be used for representing the 'virtual' accounts that allows for +/// managing multiple balances off-chain with only a single on-chain balance +/// entry. The address part can be used as a regular `Address`, and the id +/// part should be used only in the events for the off-chain processing. +/// +/// This type is only necessary in a few special cases, such as token transfers +/// that support non-custodial accounts (e.g. for the exchange support). Prefer +/// using the regular `Address` type unless multiplexing support is necessary. +/// +/// This type is compatible with `Address` at the contract interface level, i.e. +/// if a contract accepts `MuxedAddress` as an input, then its callers may still +/// pass `Address` into the call successfully. This means that if a +/// contract has upgraded its interface to switch from `Address` argument to +/// `MuxedAddress` argument, it won't break any of its existing clients. +/// +/// Currently only the regular Stellar accounts can be multiplexed, i.e. +/// multiplexed contract addresses don't exist. +/// +/// Note, that multiplexed addresses can not be used directly as a storage key. +/// This is a precaution to prevent accidental unexpected fragmentation of +/// the key space (like creating an arbitrary number of balances for the same +/// actual `Address`). +#[derive(Clone)] +pub struct MuxedAddress { + env: Env, + obj: AddressObjectWrapper, +} + +impl Debug for MuxedAddress { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(target_family = "wasm")] + match &self.obj { + AddressObjectWrapper::Address(_) => write!(f, "Address(..)"), + AddressObjectWrapper::MuxedAddress(_) => write!(f, "MuxedAddress(..)"), + } + #[cfg(not(target_family = "wasm"))] + { + use crate::env::internal::xdr; + use stellar_strkey::Strkey; + match &self.obj { + AddressObjectWrapper::Address(address_object) => { + Address::try_from_val(self.env(), address_object) + .map_err(|_| core::fmt::Error)? + .fmt(f) + } + AddressObjectWrapper::MuxedAddress(muxed_address_object) => { + let sc_val = ScVal::try_from_val(self.env(), &muxed_address_object.to_val()) + .map_err(|_| core::fmt::Error)?; + if let ScVal::Address(addr) = sc_val { + match addr { + xdr::ScAddress::MuxedAccount(muxed_account) => { + let strkey = Strkey::MuxedAccountEd25519( + stellar_strkey::ed25519::MuxedAccount { + ed25519: muxed_account.ed25519.0, + id: muxed_account.id, + }, + ); + write!(f, "MuxedAccount({})", strkey.to_string()) + } + _ => Err(core::fmt::Error), + } + } else { + Err(core::fmt::Error) + } + } + } + } + } +} + +impl Eq for MuxedAddress {} + +impl PartialEq for MuxedAddress { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for MuxedAddress { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for MuxedAddress { + fn cmp(&self, other: &Self) -> Ordering { + let v = self + .env + .obj_cmp(self.to_val(), other.to_val()) + .unwrap_infallible(); + v.cmp(&0) + } +} + +impl TryFromVal for MuxedAddress { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &MuxedAddressObject) -> Result { + Ok(unsafe { MuxedAddress::unchecked_new(env.clone(), *val) }) + } +} + +impl TryFromVal for MuxedAddress { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &AddressObject) -> Result { + Ok(unsafe { MuxedAddress::unchecked_new_from_address(env.clone(), *val) }) + } +} + +impl TryFromVal for MuxedAddress { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + if val.get_tag() == Tag::AddressObject { + Ok(AddressObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } else { + Ok(MuxedAddressObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &MuxedAddress) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&MuxedAddress) -> Result { + Ok(v.to_val()) + } +} + +impl From<&MuxedAddress> for MuxedAddress { + fn from(address: &MuxedAddress) -> Self { + address.clone() + } +} + +impl From
for MuxedAddress { + fn from(address: Address) -> Self { + (&address).into() + } +} + +impl From<&Address> for MuxedAddress { + fn from(address: &Address) -> Self { + address + .as_object() + .try_into_val(address.env()) + .unwrap_infallible() + } +} + +impl MuxedAddress { + /// Creates a `MuxedAddress` corresponding to the provided Stellar strkey. + /// + /// Supported strkey types: + /// - Account address (G...) + /// - Muxed account address (M...) + /// - Contract address (C...) + /// + /// Any other strkey type will cause this to panic. + /// + /// Prefer using the `MuxedAddress` directly as input or output argument. Only + /// use this in special cases when addresses need to be shared between + /// different environments (e.g. different chains). + pub fn from_str(env: &Env, strkey: &str) -> MuxedAddress { + let strkey_string = String::from_str(env, strkey); + MuxedAddress::from_string(&strkey_string) + } + + /// Creates a `MuxedAddress` corresponding to the provided Stellar strkey. + /// + /// Supported strkey types: + /// - Account address (G...) + /// - Muxed account address (M...) + /// - Contract address (C...) + /// + /// Any other strkey type will cause this to panic. + /// + /// Prefer using the `MuxedAddress` directly as input or output argument. Only + /// use this in special cases when addresses need to be shared between + /// different environments (e.g. different chains). + pub fn from_string(strkey: &String) -> Self { + let env = strkey.env(); + let val = internal::Env::strkey_to_muxed_address(env, strkey.to_val()).unwrap_optimized(); + MuxedAddress::try_from_val(env, &val).unwrap_optimized() + } + + /// Creates a `MuxedAddress` corresponding to the provided Stellar strkey + /// in raw bytes form. + /// + /// Supported strkey types: + /// - Account address (G...) + /// - Muxed account address (M...) + /// - Contract address (C...) + /// + /// Any other strkey type will cause this to panic. + /// + /// Prefer using the `MuxedAddress` directly as input or output argument. Only + /// use this in special cases when addresses need to be shared between + /// different environments (e.g. different chains). + pub fn from_string_bytes(strkey: &Bytes) -> Self { + let env = strkey.env(); + let val = internal::Env::strkey_to_muxed_address(env, strkey.to_val()).unwrap_optimized(); + MuxedAddress::try_from_val(env, &val).unwrap_optimized() + } + + /// Returns the `Address` part of this multiplexed address. + /// + /// The address part is necessary to perform most of the operations, such + /// as authorization or storage. + pub fn address(&self) -> Address { + match &self.obj { + AddressObjectWrapper::Address(address_object) => { + Address::try_from_val(&self.env, address_object).unwrap_infallible() + } + AddressObjectWrapper::MuxedAddress(muxed_address_object) => Address::try_from_val( + &self.env, + &internal::Env::get_address_from_muxed_address(&self.env, *muxed_address_object) + .unwrap_infallible(), + ) + .unwrap_infallible(), + } + } + + /// Returns the multiplexing identifier part of this multiplexed address, + /// if any. + /// + /// Returns `None` for the regular (non-multiplexed) addresses. + /// + /// This identifier should normally be used in the events in order to allow + /// for tracking the virtual balances associated with this address off-chain. + pub fn id(&self) -> Option { + match &self.obj { + AddressObjectWrapper::Address(_) => None, + AddressObjectWrapper::MuxedAddress(muxed_address_object) => Some( + u64::try_from_val( + &self.env, + &internal::Env::get_id_from_muxed_address(&self.env, *muxed_address_object) + .unwrap_infallible(), + ) + .unwrap(), + ), + } + } + + #[inline(always)] + pub(crate) unsafe fn unchecked_new_from_address(env: Env, obj: AddressObject) -> Self { + Self { + env, + obj: AddressObjectWrapper::Address(obj), + } + } + + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: MuxedAddressObject) -> Self { + Self { + env, + obj: AddressObjectWrapper::MuxedAddress(obj), + } + } + + #[inline(always)] + pub fn env(&self) -> &Env { + &self.env + } + + pub fn as_val(&self) -> &Val { + match &self.obj { + AddressObjectWrapper::Address(o) => o.as_val(), + AddressObjectWrapper::MuxedAddress(o) => o.as_val(), + } + } + + pub fn to_val(&self) -> Val { + match self.obj { + AddressObjectWrapper::Address(o) => o.to_val(), + AddressObjectWrapper::MuxedAddress(o) => o.to_val(), + } + } + + /// Converts this address to its Stellar strkey representation. + /// + /// Returns: + /// - `G...` for account addresses + /// - `M...` for muxed account addresses + /// - `C...` for contract addresses + pub fn to_strkey(&self) -> String { + let s = internal::Env::muxed_address_to_strkey(&self.env, self.to_val()).unwrap_optimized(); + unsafe { String::unchecked_new(self.env.clone(), s) } + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&MuxedAddress> for ScVal { + fn from(v: &MuxedAddress) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.env, &v.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for ScVal { + fn from(v: MuxedAddress) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for MuxedAddress { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + let v = Val::try_from_val(env, val)?; + match val { + ScVal::Address(sc_address) => match sc_address { + ScAddress::Account(_) | ScAddress::Contract(_) => { + Ok(AddressObject::try_from_val(env, &v)? + .try_into_val(env) + .unwrap_infallible()) + } + ScAddress::MuxedAccount(_) => Ok(MuxedAddressObject::try_from_val(env, &v)? + .try_into_val(env) + .unwrap_infallible()), + ScAddress::ClaimableBalance(_) | ScAddress::LiquidityPool(_) => { + panic!("unsupported ScAddress type") + } + }, + _ => panic!("incorrect scval type"), + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for MuxedAddress { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScAddress) -> Result { + ScVal::Address(val.clone()).try_into_val(env) + } +} + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +impl crate::testutils::MuxedAddress for MuxedAddress { + fn generate(env: &Env) -> crate::MuxedAddress { + let sc_val = ScVal::Address(crate::env::internal::xdr::ScAddress::MuxedAccount( + crate::env::internal::xdr::MuxedEd25519Account { + ed25519: crate::env::internal::xdr::Uint256( + env.with_generator(|mut g| g.address()), + ), + id: env.with_generator(|mut g| g.mux_id()), + }, + )); + sc_val.try_into_val(env).unwrap() + } + + fn new>(address: T, id: u64) -> crate::MuxedAddress { + let address: MuxedAddress = address.into(); + let sc_val = ScVal::try_from_val(&address.env, address.as_val()).unwrap(); + let account_id = match sc_val { + ScVal::Address(address) => match address { + ScAddress::MuxedAccount(muxed_account) => muxed_account.ed25519, + ScAddress::Account(crate::env::internal::xdr::AccountId( + crate::env::internal::xdr::PublicKey::PublicKeyTypeEd25519(account_id), + )) => account_id, + ScAddress::Contract(_) => panic!("contract addresses can not be multiplexed"), + ScAddress::ClaimableBalance(_) | ScAddress::LiquidityPool(_) => unreachable!(), + }, + _ => unreachable!(), + }; + let result_sc_val = ScVal::Address(ScAddress::MuxedAccount( + crate::env::internal::xdr::MuxedEd25519Account { + id, + ed25519: account_id, + }, + )); + result_sc_val.try_into_val(&address.env).unwrap() + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/num.rs b/temp_sdk/soroban-sdk-26.0.1/src/num.rs new file mode 100644 index 0000000..011c96f --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/num.rs @@ -0,0 +1,1123 @@ +use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; + +use super::{ + env::internal::{ + DurationSmall, DurationVal, Env as _, I256Object, I256Small, I256Val, TimepointSmall, + TimepointVal, U256Object, U256Small, U256Val, + }, + Bytes, ConversionError, Env, TryFromVal, TryIntoVal, Val, +}; + +#[cfg(not(target_family = "wasm"))] +use crate::env::internal::xdr::ScVal; +use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; + +macro_rules! impl_num_wrapping_val_type { + ($wrapper:ident, $val:ty, $small:ty) => { + impl Debug for $wrapper { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // FIXME: properly print it when we have the conversion functions + write!(f, "{:?}", self.val.as_val()) + } + } + + impl Eq for $wrapper {} + + impl PartialEq for $wrapper { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } + } + + impl PartialOrd for $wrapper { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } + } + + impl Ord for $wrapper { + fn cmp(&self, other: &Self) -> Ordering { + let self_raw = self.val.to_val(); + let other_raw = other.val.to_val(); + + match (<$small>::try_from(self_raw), <$small>::try_from(other_raw)) { + // Compare small numbers. + (Ok(self_num), Ok(other_num)) => self_num.cmp(&other_num), + // The object-to-small number comparisons are handled by `obj_cmp`, + // so it's safe to handle all the other cases using it. + _ => { + #[cfg(not(target_family = "wasm"))] + if !self.env.is_same_env(&other.env) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = self.env.obj_cmp(self_raw, other_raw).unwrap_infallible(); + v.cmp(&0) + } + } + } + } + + impl From<$wrapper> for $val { + #[inline(always)] + fn from(v: $wrapper) -> Self { + v.val + } + } + + impl From<&$wrapper> for $val { + #[inline(always)] + fn from(v: &$wrapper) -> Self { + v.val + } + } + + impl From<&$wrapper> for $wrapper { + #[inline(always)] + fn from(v: &$wrapper) -> Self { + v.clone() + } + } + + impl TryFromVal for $wrapper { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &$val) -> Result { + Ok(unsafe { $wrapper::unchecked_new(env.clone(), *val) }) + } + } + + impl TryFromVal for $wrapper { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(<$val>::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } + } + + impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &$wrapper) -> Result { + Ok(v.to_val()) + } + } + + impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&$wrapper) -> Result { + Ok(v.to_val()) + } + } + + #[cfg(not(target_family = "wasm"))] + impl From<&$wrapper> for ScVal { + fn from(v: &$wrapper) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + if let Ok(ss) = <$small>::try_from(v.val) { + ScVal::try_from(ss).unwrap() + } else { + ScVal::try_from_val(&v.env, &v.to_val()).unwrap() + } + } + } + + #[cfg(not(target_family = "wasm"))] + impl From<$wrapper> for ScVal { + fn from(v: $wrapper) -> Self { + (&v).into() + } + } + + #[cfg(not(target_family = "wasm"))] + impl TryFromVal for $wrapper { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok(<$val>::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible()) + } + } + + impl $wrapper { + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, val: $val) -> Self { + Self { env, val } + } + + /// Converts a `Val` known to be of this type into `Self` without + /// env-based conversion. The caller must guarantee the `Val` is of + /// the correct type; only a cheap tag check is performed. + #[inline(always)] + pub(crate) unsafe fn unchecked_from_val(env: Env, val: Val) -> Self { + Self { + env, + val: <$val>::try_from(val).unwrap_optimized(), + } + } + + #[inline(always)] + pub fn env(&self) -> &Env { + &self.env + } + + pub fn as_val(&self) -> &Val { + self.val.as_val() + } + + pub fn to_val(&self) -> Val { + self.val.to_val() + } + + pub fn to_val_type(&self) -> $val { + self.val + } + } + }; +} + +/// U256 holds a 256-bit unsigned integer. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{U256, Env}; +/// +/// let env = Env::default(); +/// let u1 = U256::from_u32(&env, 6); +/// let u2 = U256::from_u32(&env, 3); +/// assert_eq!(u1.add(&u2), U256::from_u32(&env, 9)); +/// ``` +#[derive(Clone)] +pub struct U256 { + env: Env, + val: U256Val, +} + +impl_num_wrapping_val_type!(U256, U256Val, U256Small); + +impl U256 { + pub const BITS: u32 = 256; + + /// Returns the smallest value that can be represented by this type (0). + pub fn min_value(env: &Env) -> Self { + Self::from_u32(env, 0) + } + + /// Returns the largest value that can be represented by this type (2^256 - 1). + pub fn max_value(env: &Env) -> Self { + Self::from_parts(env, u64::MAX, u64::MAX, u64::MAX, u64::MAX) + } + + fn is_zero(&self) -> bool { + *self == U256::from_u32(&self.env, 0) + } + + pub fn from_u32(env: &Env, u: u32) -> Self { + U256 { + env: env.clone(), + val: U256Val::from_u32(u), + } + } + + pub fn from_u128(env: &Env, u: u128) -> Self { + let lo_hi = (u >> 64) as u64; + let lo_lo = u as u64; + Self::from_parts(env, 0, 0, lo_hi, lo_lo) + } + + pub fn from_parts(env: &Env, hi_hi: u64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self { + let obj = env + .obj_from_u256_pieces(hi_hi, hi_lo, lo_hi, lo_lo) + .unwrap_infallible(); + U256 { + env: env.clone(), + val: obj.into(), + } + } + + pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self { + let val = env + .u256_val_from_be_bytes(bytes.to_object()) + .unwrap_infallible(); + U256 { + env: env.clone(), + val, + } + } + + pub fn to_u128(&self) -> Option { + let v = *self.val.as_val(); + + // If v is U256Small it can be converted directly + if let Ok(small) = U256Small::try_from(v) { + return Some(u64::from(small) as u128); + } + + // Otherwise use U256Object and take low sections if high are empty + let obj: U256Object = v.try_into().ok()?; + let hi_hi = self.env.obj_to_u256_hi_hi(obj).unwrap_infallible(); + let hi_lo = self.env.obj_to_u256_hi_lo(obj).unwrap_infallible(); + if hi_hi != 0 || hi_lo != 0 { + return None; + } + let lo_hi = self.env.obj_to_u256_lo_hi(obj).unwrap_infallible(); + let lo_lo = self.env.obj_to_u256_lo_lo(obj).unwrap_infallible(); + Some(((lo_hi as u128) << 64) | (lo_lo as u128)) + } + + pub fn to_be_bytes(&self) -> Bytes { + let obj = self + .env + .u256_val_to_be_bytes(self.to_val_type()) + .unwrap_infallible(); + unsafe { Bytes::unchecked_new(self.env.clone(), obj) } + } + + pub fn add(&self, other: &U256) -> U256 { + let val = self.env.u256_add(self.val, other.val).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn sub(&self, other: &U256) -> U256 { + let val = self.env.u256_sub(self.val, other.val).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn mul(&self, other: &U256) -> U256 { + let val = self.env.u256_mul(self.val, other.val).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn div(&self, other: &U256) -> U256 { + let val = self.env.u256_div(self.val, other.val).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn rem_euclid(&self, other: &U256) -> U256 { + let val = self + .env + .u256_rem_euclid(self.val, other.val) + .unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn pow(&self, pow: u32) -> U256 { + let val = self.env.u256_pow(self.val, pow.into()).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn shl(&self, bits: u32) -> U256 { + let val = self.env.u256_shl(self.val, bits.into()).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + pub fn shr(&self, bits: u32) -> U256 { + let val = self.env.u256_shr(self.val, bits.into()).unwrap_infallible(); + U256 { + env: self.env.clone(), + val, + } + } + + /// Performs checked addition. Returns `None` if overflow occurred. + pub fn checked_add(&self, other: &U256) -> Option { + let val = self + .env + .u256_checked_add(self.val, other.val) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked subtraction. Returns `None` if overflow occurred. + pub fn checked_sub(&self, other: &U256) -> Option { + let val = self + .env + .u256_checked_sub(self.val, other.val) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked multiplication. Returns `None` if overflow occurred. + pub fn checked_mul(&self, other: &U256) -> Option { + let val = self + .env + .u256_checked_mul(self.val, other.val) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked exponentiation. Returns `None` if overflow occurred. + pub fn checked_pow(&self, pow: u32) -> Option { + let val = self + .env + .u256_checked_pow(self.val, pow.into()) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked division. Returns `None` if `other` is zero. + pub fn checked_div(&self, other: &U256) -> Option { + if other.is_zero() { + return None; + } + Some(self.div(other)) + } + + /// Performs checked Euclidean remainder. Returns `None` if `other` is zero. + pub fn checked_rem_euclid(&self, other: &U256) -> Option { + if other.is_zero() { + return None; + } + Some(self.rem_euclid(other)) + } + + /// Performs checked left shift. Returns `None` if `bits >= 256`. + pub fn checked_shl(&self, bits: u32) -> Option { + if bits >= Self::BITS { + return None; + } + Some(self.shl(bits)) + } + + /// Performs checked right shift. Returns `None` if `bits >= 256`. + pub fn checked_shr(&self, bits: u32) -> Option { + if bits >= Self::BITS { + return None; + } + Some(self.shr(bits)) + } +} + +/// I256 holds a 256-bit signed integer. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{I256, Env}; +/// +/// let env = Env::default(); +/// +/// let i1 = I256::from_i32(&env, -6); +/// let i2 = I256::from_i32(&env, 3); +/// assert_eq!(i1.add(&i2), I256::from_i32(&env, -3)); +/// ``` +#[derive(Clone)] +pub struct I256 { + env: Env, + val: I256Val, +} + +impl_num_wrapping_val_type!(I256, I256Val, I256Small); + +impl I256 { + pub const BITS: u32 = 256; + + /// Returns the smallest value that can be represented by this type (-2^255). + pub fn min_value(env: &Env) -> Self { + Self::from_parts(env, i64::MIN, 0, 0, 0) + } + + /// Returns the largest value that can be represented by this type (2^255 - 1). + pub fn max_value(env: &Env) -> Self { + Self::from_parts(env, i64::MAX, u64::MAX, u64::MAX, u64::MAX) + } + + fn is_zero(&self) -> bool { + *self == I256::from_i32(&self.env, 0) + } + + fn is_neg_one(&self) -> bool { + *self == I256::from_i32(&self.env, -1) + } + + pub fn from_i32(env: &Env, i: i32) -> Self { + I256 { + env: env.clone(), + val: I256Val::from_i32(i), + } + } + + pub fn from_i128(env: &Env, i: i128) -> Self { + let lo_hi = (i >> 64) as u64; + let lo_lo = i as u64; + let (hi_hi, hi_lo) = if i < 0 { + (-1_i64, u64::MAX) // sign extend 1 bit + } else { + (0_i64, 0_u64) // sign extend 0 bit + }; + I256::from_parts(env, hi_hi, hi_lo, lo_hi, lo_lo) + } + + pub fn from_parts(env: &Env, hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self { + let obj = env + .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo) + .unwrap_infallible(); + I256 { + env: env.clone(), + val: obj.into(), + } + } + + pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self { + let val = env + .i256_val_from_be_bytes(bytes.to_object()) + .unwrap_infallible(); + I256 { + env: env.clone(), + val, + } + } + + pub fn to_i128(&self) -> Option { + let v = *self.val.as_val(); + + // If v is I256Small it can be converted directly + if let Ok(small) = I256Small::try_from(v) { + return Some(i64::from(small) as i128); + } + + // Otherwise use I256Object and take low sections if high are either + // all 1 bits or all 0 bits (negative and positive respectively) + let obj: I256Object = v.try_into().ok()?; + let hi_hi = self.env.obj_to_i256_hi_hi(obj).unwrap_infallible(); + let hi_lo = self.env.obj_to_i256_hi_lo(obj).unwrap_infallible(); + let lo_hi = self.env.obj_to_i256_lo_hi(obj).unwrap_infallible(); + let lo_lo = self.env.obj_to_i256_lo_lo(obj).unwrap_infallible(); + // The low 128 bits as an i128 + let lo = (((lo_hi as u128) << 64) | (lo_lo as u128)) as i128; + + if lo < 0 && hi_hi == -1 && hi_lo == u64::MAX { + Some(lo) // if negative low, then high must be all 1 bit + } else if 0 <= lo && hi_hi == 0 && hi_lo == 0 { + Some(lo) // if non-negative low, then high must be all 0 bit + } else { + None + } + } + + pub fn to_be_bytes(&self) -> Bytes { + let obj = self + .env + .i256_val_to_be_bytes(self.to_val_type()) + .unwrap_infallible(); + unsafe { Bytes::unchecked_new(self.env.clone(), obj) } + } + + pub fn add(&self, other: &I256) -> I256 { + let val = self.env.i256_add(self.val, other.val).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn sub(&self, other: &I256) -> I256 { + let val = self.env.i256_sub(self.val, other.val).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn mul(&self, other: &I256) -> I256 { + let val = self.env.i256_mul(self.val, other.val).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn div(&self, other: &I256) -> I256 { + let val = self.env.i256_div(self.val, other.val).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn rem_euclid(&self, other: &I256) -> I256 { + let val = self + .env + .i256_rem_euclid(self.val, other.val) + .unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn pow(&self, pow: u32) -> I256 { + let val = self.env.i256_pow(self.val, pow.into()).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn shl(&self, bits: u32) -> I256 { + let val = self.env.i256_shl(self.val, bits.into()).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + pub fn shr(&self, bits: u32) -> I256 { + let val = self.env.i256_shr(self.val, bits.into()).unwrap_infallible(); + I256 { + env: self.env.clone(), + val, + } + } + + /// Performs checked addition. Returns `None` if overflow occurred. + pub fn checked_add(&self, other: &I256) -> Option { + let val = self + .env + .i256_checked_add(self.val, other.val) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked subtraction. Returns `None` if overflow occurred. + pub fn checked_sub(&self, other: &I256) -> Option { + let val = self + .env + .i256_checked_sub(self.val, other.val) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked multiplication. Returns `None` if overflow occurred. + pub fn checked_mul(&self, other: &I256) -> Option { + let val = self + .env + .i256_checked_mul(self.val, other.val) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Performs checked exponentiation. Returns `None` if overflow occurred. + pub fn checked_pow(&self, pow: u32) -> Option { + let val = self + .env + .i256_checked_pow(self.val, pow.into()) + .unwrap_infallible(); + if val.is_void() { + None + } else { + Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) + } + } + + /// Returns `true` if dividing `self` by `other` would overflow or divide by zero. + /// This covers: `other == 0`, or `self == I256::MIN && other == -1`. + fn is_div_overflow(&self, other: &I256) -> bool { + if other.is_zero() { + return true; + } + if other.is_neg_one() { + let min = I256::min_value(&self.env); + if *self == min { + return true; + } + } + false + } + + /// Performs checked division. Returns `None` if `other` is zero, or if + /// `self` is `I256::MIN` and `other` is `-1` (overflow). + pub fn checked_div(&self, other: &I256) -> Option { + if self.is_div_overflow(other) { + return None; + } + Some(self.div(other)) + } + + /// Performs checked Euclidean remainder. Returns `None` if `other` is zero, + /// or if `self` is `I256::MIN` and `other` is `-1` (overflow in intermediate + /// division). + pub fn checked_rem_euclid(&self, other: &I256) -> Option { + if self.is_div_overflow(other) { + return None; + } + Some(self.rem_euclid(other)) + } + + /// Performs checked left shift. Returns `None` if `bits >= 256`. + pub fn checked_shl(&self, bits: u32) -> Option { + if bits >= Self::BITS { + return None; + } + Some(self.shl(bits)) + } + + /// Performs checked right shift. Returns `None` if `bits >= 256`. + pub fn checked_shr(&self, bits: u32) -> Option { + if bits >= Self::BITS { + return None; + } + Some(self.shr(bits)) + } +} + +#[doc = "Timepoint holds a 64-bit unsigned integer."] +#[derive(Clone)] +pub struct Timepoint { + env: Env, + val: TimepointVal, +} + +impl_num_wrapping_val_type!(Timepoint, TimepointVal, TimepointSmall); + +impl Timepoint { + /// Create a Timepoint from a unix time in seconds, the time in seconds + /// since January 1, 1970 UTC. + pub fn from_unix(env: &Env, seconds: u64) -> Timepoint { + let val = TimepointVal::try_from_val(env, &seconds).unwrap_optimized(); + Timepoint { + env: env.clone(), + val, + } + } + + /// Returns the Timepoint as unix time in seconds, the time in seconds since + /// January 1, 1970 UTC. + pub fn to_unix(&self) -> u64 { + u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized() + } +} + +#[doc = "Duration holds a 64-bit unsigned integer."] +#[derive(Clone)] +pub struct Duration { + env: Env, + val: DurationVal, +} + +impl_num_wrapping_val_type!(Duration, DurationVal, DurationSmall); + +impl Duration { + /// Create a Duration from seconds. + pub fn from_seconds(env: &Env, seconds: u64) -> Duration { + let val = DurationVal::try_from_val(env, &seconds).unwrap_optimized(); + Duration { + env: env.clone(), + val, + } + } + + /// Returns the Duration as seconds. + pub fn to_seconds(&self) -> u64 { + u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_u256_roundtrip() { + let env = Env::default(); + + let u1 = U256::from_u32(&env, 12345); + let bytes = u1.to_be_bytes(); + let u2 = U256::from_be_bytes(&env, &bytes); + assert_eq!(u1, u2); + } + + #[test] + fn test_u256_u128_conversion() { + let env = Env::default(); + + // positive + let start = u128::MAX / 7; + let from = U256::from_u128(&env, start); + let end = from.to_u128().unwrap(); + assert_eq!(start, end); + + let over_u128 = from.mul(&U256::from_u32(&env, 8)); + let failure = over_u128.to_u128(); + assert_eq!(failure, None); + + // zero + let start = 0_u128; + let from = U256::from_u128(&env, start); + let end = from.to_u128().unwrap(); + assert_eq!(start, end); + + // small (exercises the U256Small fast-path in to_u128) + let from_small = U256::from_u32(&env, 0); + assert_eq!(from_small.to_u128(), Some(0_u128)); + + let from_small = U256::from_u32(&env, u32::MAX); + assert_eq!(from_small.to_u128(), Some(u32::MAX as u128)); + } + + #[test] + fn test_i256_roundtrip() { + let env = Env::default(); + + let i1 = I256::from_i32(&env, -12345); + let bytes = i1.to_be_bytes(); + let i2 = I256::from_be_bytes(&env, &bytes); + assert_eq!(i1, i2); + } + + #[test] + fn test_i256_i128_conversion() { + let env = Env::default(); + + // positive + let start = i128::MAX / 7; + let from = I256::from_i128(&env, start); + let end = from.to_i128().unwrap(); + assert_eq!(start, end); + + let over_i128 = from.mul(&I256::from_i32(&env, 8)); + let failure = over_i128.to_i128(); + assert_eq!(failure, None); + + // negative + let start = i128::MIN / 7; + let from = I256::from_i128(&env, start); + let end = from.to_i128().unwrap(); + assert_eq!(start, end); + + let over_i128 = from.mul(&I256::from_i32(&env, 8)); + let failure = over_i128.to_i128(); + assert_eq!(failure, None); + + // zero + let start = 0_i128; + let from = I256::from_i128(&env, start); + let end = from.to_i128().unwrap(); + assert_eq!(start, end); + + // small (exercises the I256Small fast-path in to_i128) + let from_small = I256::from_i32(&env, 0); + assert_eq!(from_small.to_i128(), Some(0_i128)); + + let from_small = I256::from_i32(&env, i32::MAX); + assert_eq!(from_small.to_i128(), Some(i32::MAX as i128)); + + let from_small = I256::from_i32(&env, i32::MIN); + assert_eq!(from_small.to_i128(), Some(i32::MIN as i128)); + } + + #[test] + fn test_timepoint_roundtrip() { + let env = Env::default(); + + let tp = Timepoint::from_unix(&env, 123); + let u = tp.to_unix(); + assert_eq!(u, 123); + } + + #[test] + fn test_duration_roundtrip() { + let env = Env::default(); + + let tp = Duration::from_seconds(&env, 123); + let u = tp.to_seconds(); + assert_eq!(u, 123); + } + + #[test] + fn test_u256_arith() { + let env = Env::default(); + + let u1 = U256::from_u32(&env, 6); + let u2 = U256::from_u32(&env, 3); + assert_eq!(u1.add(&u2), U256::from_u32(&env, 9)); + assert_eq!(u1.sub(&u2), U256::from_u32(&env, 3)); + assert_eq!(u1.mul(&u2), U256::from_u32(&env, 18)); + assert_eq!(u1.div(&u2), U256::from_u32(&env, 2)); + assert_eq!(u1.pow(2), U256::from_u32(&env, 36)); + assert_eq!(u1.shl(2), U256::from_u32(&env, 24)); + assert_eq!(u1.shr(1), U256::from_u32(&env, 3)); + + let u3 = U256::from_u32(&env, 7); + let u4 = U256::from_u32(&env, 4); + assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3)); + } + + #[test] + fn test_u256_min() { + let env = Env::default(); + + let min = U256::min_value(&env); + assert_eq!(min, U256::from_u32(&env, 0)); + + let one = U256::from_u32(&env, 1); + assert_eq!(min.checked_sub(&one), None); + assert!(min.checked_add(&one).is_some()); + } + + #[test] + fn test_u256_max() { + let env = Env::default(); + + let max = U256::max_value(&env); + assert_eq!( + max, + U256::from_parts(&env, u64::MAX, u64::MAX, u64::MAX, u64::MAX) + ); + + let u128_max = U256::from_u128(&env, u128::MAX); + assert!(max > u128_max); + + let one = U256::from_u32(&env, 1); + assert_eq!(max.checked_add(&one), None); + assert!(max.checked_sub(&one).is_some()); + } + + #[test] + fn test_u256_checked_arith() { + let env = Env::default(); + + let u1 = U256::from_u32(&env, 6); + let u2 = U256::from_u32(&env, 3); + assert_eq!(u1.checked_add(&u2), Some(U256::from_u32(&env, 9))); + assert_eq!(u1.checked_sub(&u2), Some(U256::from_u32(&env, 3))); + assert_eq!(u1.checked_mul(&u2), Some(U256::from_u32(&env, 18))); + assert_eq!(u1.checked_div(&u2), Some(U256::from_u32(&env, 2))); + assert_eq!(u1.checked_pow(2), Some(U256::from_u32(&env, 36))); + assert_eq!(u1.checked_shl(2), Some(U256::from_u32(&env, 24))); + assert_eq!(u1.checked_shr(1), Some(U256::from_u32(&env, 3))); + + let u3 = U256::from_u32(&env, 7); + let u4 = U256::from_u32(&env, 4); + assert_eq!(u3.checked_rem_euclid(&u4), Some(U256::from_u32(&env, 3))); + } + + #[test] + fn test_u256_checked_arith_overflow() { + let env = Env::default(); + + let zero = U256::from_u32(&env, 0); + let one = U256::from_u32(&env, 1); + let two = U256::from_u32(&env, 2); + let max = U256::max_value(&env); + assert_eq!(max.checked_add(&one), None); + assert_eq!(zero.checked_sub(&one), None); + assert_eq!(max.checked_mul(&two), None); + assert_eq!(one.checked_div(&zero), None); + assert_eq!(max.checked_pow(2), None); + assert_eq!(one.checked_shl(256), None); + assert_eq!(one.checked_shr(256), None); + assert_eq!(one.checked_rem_euclid(&zero), None); + + let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0); + let one_from_parts = U256::from_parts(&env, 0, 0, 0, 1); + assert_eq!(one.checked_div(&zero_from_parts), None); + assert_eq!(zero.checked_sub(&one_from_parts), None); + } + + #[test] + fn test_u256_is_zero() { + let env = Env::default(); + + let zero = U256::from_u32(&env, 0); + let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0); + let non_zero = U256::from_u32(&env, 1); + + assert!(zero.is_zero()); + assert!(zero_from_parts.is_zero()); + assert!(!non_zero.is_zero()); + } + + #[test] + fn test_i256_arith() { + let env = Env::default(); + + let i1 = I256::from_i32(&env, -6); + let i2 = I256::from_i32(&env, 3); + assert_eq!(i1.add(&i2), I256::from_i32(&env, -3)); + assert_eq!(i1.sub(&i2), I256::from_i32(&env, -9)); + assert_eq!(i1.mul(&i2), I256::from_i32(&env, -18)); + assert_eq!(i1.div(&i2), I256::from_i32(&env, -2)); + assert_eq!(i1.pow(2), I256::from_i32(&env, 36)); + assert_eq!(i1.shl(2), I256::from_i32(&env, -24)); + assert_eq!(i1.shr(1), I256::from_i32(&env, -3)); + + let u3 = I256::from_i32(&env, -7); + let u4 = I256::from_i32(&env, 4); + assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1)); + } + + #[test] + fn test_i256_min() { + let env = Env::default(); + + let min = I256::min_value(&env); + assert_eq!(min, I256::from_parts(&env, i64::MIN, 0, 0, 0)); + + let i128_min = I256::from_i128(&env, i128::MIN); + assert!(min < i128_min); + + let one = I256::from_i32(&env, 1); + assert_eq!(min.checked_sub(&one), None); + assert!(min.checked_add(&one).is_some()); + } + + #[test] + fn test_i256_max() { + let env = Env::default(); + + let max = I256::max_value(&env); + assert_eq!( + max, + I256::from_parts(&env, i64::MAX, u64::MAX, u64::MAX, u64::MAX) + ); + + let i128_max = I256::from_i128(&env, i128::MAX); + assert!(max > i128_max); + + let one = I256::from_i32(&env, 1); + assert_eq!(max.checked_add(&one), None); + assert!(max.checked_sub(&one).is_some()); + } + + #[test] + fn test_i256_checked_arith() { + let env = Env::default(); + + let i1 = I256::from_i32(&env, -6); + let i2 = I256::from_i32(&env, 3); + assert_eq!(i1.checked_add(&i2), Some(I256::from_i32(&env, -3))); + assert_eq!(i1.checked_sub(&i2), Some(I256::from_i32(&env, -9))); + assert_eq!(i1.checked_mul(&i2), Some(I256::from_i32(&env, -18))); + assert_eq!(i1.checked_div(&i2), Some(I256::from_i32(&env, -2))); + assert_eq!(i1.checked_pow(2), Some(I256::from_i32(&env, 36))); + assert_eq!(i1.checked_shl(2), Some(I256::from_i32(&env, -24))); + assert_eq!(i1.checked_shr(1), Some(I256::from_i32(&env, -3))); + + let u3 = I256::from_i32(&env, -7); + let u4 = I256::from_i32(&env, 4); + assert_eq!(u3.checked_rem_euclid(&u4), Some(I256::from_i32(&env, 1))); + } + + #[test] + fn test_i256_checked_arith_overflow() { + let env = Env::default(); + + let zero = I256::from_i32(&env, 0); + let one = I256::from_i32(&env, 1); + let negative_one = I256::from_i32(&env, -1); + let two = I256::from_i32(&env, 2); + let max = I256::max_value(&env); + let min = I256::min_value(&env); + assert_eq!(max.checked_add(&one), None); + assert_eq!(min.checked_sub(&one), None); + assert_eq!(max.checked_mul(&two), None); + assert_eq!(one.checked_div(&zero), None); + assert_eq!(min.checked_div(&negative_one), None); + assert_eq!(max.checked_pow(2), None); + assert_eq!(one.checked_shl(256), None); + assert_eq!(one.checked_shr(256), None); + assert_eq!(one.checked_rem_euclid(&zero), None); + + let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0); + let one_from_parts = I256::from_parts(&env, 0, 0, 0, 1); + assert_eq!(one.checked_div(&zero_from_parts), None); + assert_eq!(min.checked_sub(&one_from_parts), None); + } + + #[test] + fn test_i256_is_zero() { + let env = Env::default(); + + let zero = I256::from_i32(&env, 0); + let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0); + let non_zero = I256::from_i32(&env, 1); + + assert!(zero.is_zero()); + assert!(zero_from_parts.is_zero()); + assert!(!non_zero.is_zero()); + } + + #[test] + fn test_i256_is_neg_one() { + let env = Env::default(); + + let negative_one = I256::from_i32(&env, -1); + let negative_one_from_parts = I256::from_parts(&env, -1, u64::MAX, u64::MAX, u64::MAX); + let negative_two = I256::from_i32(&env, -2); + + assert!(negative_one.is_neg_one()); + assert!(negative_one_from_parts.is_neg_one()); + assert!(!negative_two.is_neg_one()); + } + + #[test] + fn test_i256_is_div_overflow() { + let env = Env::default(); + + let zero = I256::from_i32(&env, 0); + let negative_one = I256::from_i32(&env, -1); + let min = I256::min_value(&env); + + assert!(!zero.is_div_overflow(&negative_one)); + + assert!(negative_one.is_div_overflow(&zero)); + assert!(min.is_div_overflow(&negative_one)); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/prng.rs b/temp_sdk/soroban-sdk-26.0.1/src/prng.rs new file mode 100644 index 0000000..cf28a07 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/prng.rs @@ -0,0 +1,586 @@ +//! Prng contains a pseudo-random number generator. +//! +//! ## Warning +//! +//! Do not use the PRNG in this module without a clear understanding of two +//! major limitations in the way it is deployed in the Stellar network: +//! +//! 1. The PRNG is seeded with data that is public as soon as each ledger is +//! nominated. Therefore it **should never be used to generate secrets**. +//! +//! 2. The PRNG is seeded with data that is under the control of validators. +//! Therefore it **should only be used in applications where the risk of +//! validator influence is acceptable**. +//! +//! The PRNG in this module is a strong CSPRNG (ChaCha20) and can be manually +//! re-seeded by contracts, in order to support commit/reveal schemes, oracles, +//! or similar advanced types of pseudo-random contract behaviour. Any PRNG is +//! however only as strong as its seed. +//! +//! The network runs in strict consensus, so every node in the network seeds its +//! PRNG with a consensus value, **not a random entropy source**. It uses data +//! that is generally difficult to predict in advance, and generally difficult +//! for network **users** to bias to a specific value: the seed is derived from +//! the overall transaction-set hash and the hash-sorted position number of each +//! transaction within it. But this seed is **not secret** and **not +//! cryptographically hard to bias** if a corrupt **validator** were to choose +//! to do so (similar to the way a corrupt validator can bias overall +//! transaction admission in the network). +//! +//! In other words the network will provide a stronger seed than a contract +//! could likely derive on-chain using any other public data visible to it (eg. +//! better than using a timestamp, ledger number, counter, or a similarly weak +//! seed) but weaker than a contract could acquire using a commit/reveal scheme +//! with an off-chain source of trusted random entropy. +//! +//! You should carefully consider whether these limitations are acceptable for +//! your application before using this module. +//! +//! ## Operation +//! +//! The host has a single hidden "base" PRNG that is seeded by the network. The +//! base PRNG is then used to seed separate, independent "local" PRNGs for each +//! contract invocation. This independence has the following characteristics: +//! +//! - Contract invocations can only access (use or reseed) their local PRNG. +//! - Contract invocations cannot influence any other invocation's local PRNG, +//! except by influencing the other invocation to make a call to its PRNG. +//! - Contracts cannot influence the base PRNG that seeds local PRNGs, except +//! by making calls and thereby creating new local PRNGs with new seeds. +//! - A contract invocation's local PRNG maintains state through the life of +//! the invocation. +//! - That state is advanced by each call from the invocation to a PRNG +//! function in this module. +//! - A contract invocation's local PRNG is destroyed after the invocation. +//! - Any re-entry of a contract counts as a separate invocation. +//! +//! ## Testing +//! +//! In local tests, the base PRNG of each host is seeded to zero when the host +//! is constructed, so each contract invocation's local PRNG seed (and all its +//! PRNG-derived calls) will be determined strictly by its order of invocation +//! in the test. Assuming this order is stable, each test run should see stable +//! output from the local PRNG. +use core::ops::{Bound, RangeBounds}; + +use crate::{ + env::internal, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Bytes, BytesN, Env, IntoVal, Vec, +}; + +/// Prng is a pseudo-random generator. +/// +/// # Warning +/// +/// **The PRNG is unsuitable for generating secrets or use in applications with +/// low risk tolerance, see the module-level comment.** +pub struct Prng { + env: Env, +} + +impl Prng { + pub(crate) fn new(env: &Env) -> Prng { + Prng { env: env.clone() } + } + + pub fn env(&self) -> &Env { + &self.env + } + + /// Reseeds the PRNG with the provided value. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + pub fn seed(&self, seed: Bytes) { + let env = self.env(); + debug_assert_in_contract!(env); + internal::Env::prng_reseed(env, seed.into()).unwrap_infallible(); + } + + /// Fills the type with a random value. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + /// + /// # Examples + /// + /// ## `u64` + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// let mut value: u64 = 0; + /// env.prng().fill(&mut value); + /// assert_eq!(value, 8478755077819529274); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + /// + /// ## `[u8]` + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// let mut value = [0u8; 32]; + /// env.prng().fill(&mut value); + /// assert_eq!( + /// value, + /// [ + /// 58, 248, 248, 38, 210, 150, 170, 117, 122, 110, 9, 101, 244, 57, + /// 221, 102, 164, 48, 43, 104, 222, 229, 242, 29, 25, 148, 88, 204, + /// 130, 148, 2, 66 + /// ], + /// ); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + pub fn fill(&self, v: &mut T) + where + T: Fill + ?Sized, + { + v.fill(self); + } + + /// Returns a random value of the given type. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + /// + /// # Examples + /// + /// ## `u64` + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// let value: u64 = env.prng().gen(); + /// assert_eq!(value, 8478755077819529274); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + /// + /// ## `[u8; N]` + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// let value: [u8; 32] = env.prng().gen(); + /// assert_eq!( + /// value, + /// [ + /// 58, 248, 248, 38, 210, 150, 170, 117, 122, 110, 9, 101, 244, 57, + /// 221, 102, 164, 48, 43, 104, 222, 229, 242, 29, 25, 148, 88, 204, + /// 130, 148, 2, 66 + /// ], + /// ); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + pub fn gen(&self) -> T + where + T: Gen, + { + T::gen(self) + } + + /// Returns a random value of the given type with the given length. + /// + /// # Panics + /// + /// If the length is greater than u32::MAX. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + /// + /// # Examples + /// + /// ## `Bytes` + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// // Get a value of length 32 bytes. + /// let value: Bytes = env.prng().gen_len(32); + /// assert_eq!(value, Bytes::from_slice( + /// &env, + /// &[ + /// 58, 248, 248, 38, 210, 150, 170, 117, 122, 110, 9, 101, 244, 57, + /// 221, 102, 164, 48, 43, 104, 222, 229, 242, 29, 25, 148, 88, 204, + /// 130, 148, 2, 66 + /// ], + /// )); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + pub fn gen_len(&self, len: T::Len) -> T + where + T: GenLen, + { + T::gen_len(self, len) + } + + /// Returns a random value of the given type in the range specified. + /// + /// # Panics + /// + /// If the start of the range is greater than the end. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + /// + /// # Examples + /// + /// ## `u64` + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// // Get a value in the range of 1 to 100, inclusive. + /// let value: u64 = env.prng().gen_range(1..=100); + /// assert_eq!(value, 46); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + pub fn gen_range(&self, r: impl RangeBounds) -> T + where + T: GenRange, + { + T::gen_range(self, r) + } + + /// Returns a random u64 in the range specified. + /// + /// # Panics + /// + /// If the range is empty. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + /// + /// # Examples + /// + /// ``` + /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; + /// # + /// # #[contract] + /// # pub struct Contract; + /// # + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// # let contract_id = env.register(Contract, ()); + /// # env.as_contract(&contract_id, || { + /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); + /// // Get a value in the range of 1 to 100, inclusive. + /// let value = env.prng().u64_in_range(1..=100); + /// assert_eq!(value, 46); + /// # }) + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + #[deprecated(note = "use env.prng().gen_range(...)")] + pub fn u64_in_range(&self, r: impl RangeBounds) -> u64 { + self.gen_range(r) + } + + /// Shuffles a value using the Fisher-Yates algorithm. + /// + /// # Warning + /// + /// **The PRNG is unsuitable for generating secrets or use in applications with + /// low risk tolerance, see the module-level comment.** + pub fn shuffle(&self, v: &mut T) + where + T: Shuffle, + { + v.shuffle(self); + } +} + +impl Shuffle for Vec { + fn shuffle(&mut self, prng: &Prng) { + let env = prng.env(); + debug_assert_in_contract!(env); + let obj = internal::Env::prng_vec_shuffle(env, self.to_object()).unwrap_infallible(); + *self = unsafe { Self::unchecked_new(env.clone(), obj) }; + } +} + +/// Implemented by types that support being filled by a Prng. +pub trait Fill { + /// Fills the given value with the Prng. + fn fill(&mut self, prng: &Prng); +} + +/// Implemented by types that support being generated by a Prng. +pub trait Gen { + /// Generates a value of the implementing type with the Prng. + fn gen(prng: &Prng) -> Self; +} + +/// Implemented by types that support being generated of specific length by a +/// Prng. +pub trait GenLen { + type Len; + + /// Generates a value of the given implementing type with length with the + /// Prng. + /// + /// # Panics + /// + /// If the length is greater than u32::MAX. + fn gen_len(prng: &Prng, len: Self::Len) -> Self; +} + +/// Implemented by types that support being generated in a specific range by a +/// Prng. +pub trait GenRange { + type RangeBound; + + /// Generates a value of the implementing type with the Prng in the + /// specified range. + /// + /// # Panics + /// + /// If the range is empty. + fn gen_range(prng: &Prng, r: impl RangeBounds) -> Self; +} + +/// Implemented by types that support being shuffled by a Prng. +pub trait Shuffle { + /// Shuffles the value with the Prng. + fn shuffle(&mut self, prng: &Prng); +} + +/// Implemented by types that support being shuffled by a Prng. +pub trait ToShuffled { + type Shuffled; + fn to_shuffled(&self, prng: &Prng) -> Self::Shuffled; +} + +impl ToShuffled for T { + type Shuffled = Self; + fn to_shuffled(&self, prng: &Prng) -> Self { + let mut copy = self.clone(); + copy.shuffle(prng); + copy + } +} + +impl Fill for u64 { + fn fill(&mut self, prng: &Prng) { + *self = Self::gen(prng); + } +} + +impl Gen for u64 { + fn gen(prng: &Prng) -> Self { + let env = prng.env(); + debug_assert_in_contract!(env); + internal::Env::prng_u64_in_inclusive_range(env, u64::MIN, u64::MAX).unwrap_infallible() + } +} + +impl GenRange for u64 { + type RangeBound = u64; + + fn gen_range(prng: &Prng, r: impl RangeBounds) -> Self { + let env = prng.env(); + debug_assert_in_contract!(env); + let start_bound = match r.start_bound() { + Bound::Included(b) => *b, + Bound::Excluded(b) => b + .checked_add(1) + .expect_optimized("attempt to add with overflow"), + Bound::Unbounded => u64::MIN, + }; + let end_bound = match r.end_bound() { + Bound::Included(b) => *b, + Bound::Excluded(b) => b + .checked_sub(1) + .expect_optimized("attempt to subtract with overflow"), + Bound::Unbounded => u64::MAX, + }; + internal::Env::prng_u64_in_inclusive_range(env, start_bound, end_bound).unwrap_infallible() + } +} + +impl Fill for Bytes { + /// Fills the Bytes with the Prng. + /// + /// # Panics + /// + /// If the length of Bytes is greater than u32::MAX in length. + fn fill(&mut self, prng: &Prng) { + let env = prng.env(); + debug_assert_in_contract!(env); + let len: u32 = self.len(); + let obj = internal::Env::prng_bytes_new(env, len.into()).unwrap_infallible(); + *self = unsafe { Bytes::unchecked_new(env.clone(), obj) }; + } +} + +impl GenLen for Bytes { + type Len = u32; + /// Generates the Bytes with the Prng of the given length. + fn gen_len(prng: &Prng, len: u32) -> Self { + let env = prng.env(); + debug_assert_in_contract!(env); + let obj = internal::Env::prng_bytes_new(env, len.into()).unwrap_infallible(); + unsafe { Bytes::unchecked_new(env.clone(), obj) } + } +} + +impl Fill for BytesN { + /// Fills the BytesN with the Prng. + /// + /// # Panics + /// + /// If the length of BytesN is greater than u32::MAX in length. + fn fill(&mut self, prng: &Prng) { + let bytesn = Self::gen(prng); + *self = bytesn; + } +} + +impl Gen for BytesN { + /// Generates the BytesN with the Prng. + /// + /// # Panics + /// + /// If the length of BytesN is greater than u32::MAX in length. + fn gen(prng: &Prng) -> Self { + let env = prng.env(); + debug_assert_in_contract!(env); + let len: u32 = N.try_into().unwrap_optimized(); + let obj = internal::Env::prng_bytes_new(env, len.into()).unwrap_infallible(); + unsafe { BytesN::unchecked_new(env.clone(), obj) } + } +} + +impl Fill for [u8] { + /// Fills the slice with the Prng. + /// + /// # Panics + /// + /// If the slice is greater than u32::MAX in length. + fn fill(&mut self, prng: &Prng) { + let env = prng.env(); + debug_assert_in_contract!(env); + let len: u32 = self.len().try_into().unwrap_optimized(); + let bytes: Bytes = internal::Env::prng_bytes_new(env, len.into()) + .unwrap_infallible() + .into_val(env); + bytes.copy_into_slice(self); + } +} + +impl Fill for [u8; N] { + /// Fills the array with the Prng. + /// + /// # Panics + /// + /// If the array is greater than u32::MAX in length. + fn fill(&mut self, prng: &Prng) { + let env = prng.env(); + debug_assert_in_contract!(env); + let len: u32 = N.try_into().unwrap_optimized(); + let bytes: Bytes = internal::Env::prng_bytes_new(env, len.into()) + .unwrap_infallible() + .into_val(env); + bytes.copy_into_slice(self); + } +} + +impl Gen for [u8; N] { + /// Generates the array with the Prng. + /// + /// # Panics + /// + /// If the array is greater than u32::MAX in length. + fn gen(prng: &Prng) -> Self { + let mut v = [0u8; N]; + v.fill(prng); + v + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs b/temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs new file mode 100644 index 0000000..11b84a2 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs @@ -0,0 +1,433 @@ +//! SpecShakingMarker is an internal trait used to ensure that contract type specs +//! are included in the WASM binary when types are used at contract boundaries. +//! +//! The trait is called at three external boundary points: +//! 1. Contract function input parameters +//! 2. Contract function return values +//! 3. Event publishing +//! +//! Types that are only used internally (storage, cross-contract calls) do not +//! need their specs included, so the trait is NOT called from general TryFromVal +//! conversions. +//! +//! The trait has a default no-op implementation. Types generated by contracttype, +//! contractevent, and contracterror macros implement this trait to include their +//! spec XDR in the WASM's contractspecv0 section. +//! +//! Types whose layout includes their inner types inline (`Option`, +//! `Result`, tuples) call `T::spec_shaking_marker()` directly for +//! each inner type. +//! +//! Types whose size is independent of their inner types (`Vec`, +//! `Map`, `&T`, `&mut T`) use [`keep_reachable`] to reference each +//! inner type's marker without calling it. Recursive definitions are +//! possible through these types, so a direct call would risk a runtime cycle. + +/// Trait for types that may include their spec in the WASM binary. +/// +/// This trait is used internally by the SDK to ensure contract type specs +/// are included when types are used at external boundaries (function params, +/// return values, events). +/// +/// Types with `#[contracttype]`, `#[contractevent]`, or `#[contracterror]` +/// will have implementations that include their spec. All other types have +/// a no-op implementation. +#[doc(hidden)] +pub trait SpecShakingMarker { + /// Include this type's spec in the WASM binary. + /// + /// For primitive types and built-in SDK types, this is a no-op. + /// For user-defined contract types, this ensures the spec XDR is + /// included in the contractspecv0 section. + #[inline(always)] + fn spec_shaking_marker() {} +} + +/// Keeps `f`'s symbol alive through the linker's dead-code-elimination +/// pass without invoking `f` at runtime. Takes `f` as a function pointer +/// and volatile-reads it. The same technique is used to keep the `MARKER` +/// byte statics alive (see `soroban-sdk-macros/src/shaking.rs`). +#[doc(hidden)] +#[inline(always)] +fn keep_reachable(_f: fn()) { + #[cfg(target_family = "wasm")] + let _ = unsafe { core::ptr::read_volatile(&_f) }; +} + +// Primitive type implementations (no-op) +impl SpecShakingMarker for () {} +impl SpecShakingMarker for bool {} +impl SpecShakingMarker for u32 {} +impl SpecShakingMarker for i32 {} +impl SpecShakingMarker for u64 {} +impl SpecShakingMarker for i64 {} +impl SpecShakingMarker for u128 {} +impl SpecShakingMarker for i128 {} + +// Reference implementations — use `keep_reachable` because &T is +// pointer-sized independent of T, so recursive definitions through +// references could be possible. Currently, limitations of generics +// within `map_type` prevent this from working, so this is done +// out of caution. +impl SpecShakingMarker for &T { + #[inline(always)] + fn spec_shaking_marker() { + keep_reachable(T::spec_shaking_marker); + } +} + +impl SpecShakingMarker for &mut T { + #[inline(always)] + fn spec_shaking_marker() { + keep_reachable(T::spec_shaking_marker); + } +} + +// Option implementation - includes inner type's spec +impl SpecShakingMarker for Option { + #[inline(always)] + fn spec_shaking_marker() { + T::spec_shaking_marker(); + } +} + +// Result implementation - includes both types' specs +impl SpecShakingMarker for Result { + #[inline(always)] + fn spec_shaking_marker() { + T::spec_shaking_marker(); + E::spec_shaking_marker(); + } +} + +// Tuple implementations +impl SpecShakingMarker for (T0,) { + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + } +} + +impl SpecShakingMarker for (T0, T1) { + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + } +} + +impl SpecShakingMarker + for (T0, T1, T2) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + T7: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + T7::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + T7: SpecShakingMarker, + T8: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + T7::spec_shaking_marker(); + T8::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + T7: SpecShakingMarker, + T8: SpecShakingMarker, + T9: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + T7::spec_shaking_marker(); + T8::spec_shaking_marker(); + T9::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + T7: SpecShakingMarker, + T8: SpecShakingMarker, + T9: SpecShakingMarker, + T10: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + T7::spec_shaking_marker(); + T8::spec_shaking_marker(); + T9::spec_shaking_marker(); + T10::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + T7: SpecShakingMarker, + T8: SpecShakingMarker, + T9: SpecShakingMarker, + T10: SpecShakingMarker, + T11: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + T7::spec_shaking_marker(); + T8::spec_shaking_marker(); + T9::spec_shaking_marker(); + T10::spec_shaking_marker(); + T11::spec_shaking_marker(); + } +} + +impl< + T0: SpecShakingMarker, + T1: SpecShakingMarker, + T2: SpecShakingMarker, + T3: SpecShakingMarker, + T4: SpecShakingMarker, + T5: SpecShakingMarker, + T6: SpecShakingMarker, + T7: SpecShakingMarker, + T8: SpecShakingMarker, + T9: SpecShakingMarker, + T10: SpecShakingMarker, + T11: SpecShakingMarker, + T12: SpecShakingMarker, + > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) +{ + #[inline(always)] + fn spec_shaking_marker() { + T0::spec_shaking_marker(); + T1::spec_shaking_marker(); + T2::spec_shaking_marker(); + T3::spec_shaking_marker(); + T4::spec_shaking_marker(); + T5::spec_shaking_marker(); + T6::spec_shaking_marker(); + T7::spec_shaking_marker(); + T8::spec_shaking_marker(); + T9::spec_shaking_marker(); + T10::spec_shaking_marker(); + T11::spec_shaking_marker(); + T12::spec_shaking_marker(); + } +} + +// SDK type implementations (no-op for built-in types, propagate for containers) +// These are imported via crate:: to avoid circular dependencies + +impl SpecShakingMarker for crate::Address {} +impl SpecShakingMarker for crate::Bytes {} +impl SpecShakingMarker for crate::BytesN {} +impl SpecShakingMarker for crate::String {} +impl SpecShakingMarker for crate::Symbol {} +impl SpecShakingMarker for crate::U256 {} +impl SpecShakingMarker for crate::I256 {} +impl SpecShakingMarker for crate::Timepoint {} +impl SpecShakingMarker for crate::Duration {} +impl SpecShakingMarker for crate::Val {} +impl SpecShakingMarker for crate::Error {} + +// SDK Container types - Vec and Map use `keep_reachable` to allow for recursive definitions. +impl SpecShakingMarker for crate::Vec { + #[inline(always)] + fn spec_shaking_marker() { + keep_reachable(T::spec_shaking_marker); + } +} + +impl SpecShakingMarker for crate::Map { + #[inline(always)] + fn spec_shaking_marker() { + keep_reachable(K::spec_shaking_marker); + keep_reachable(V::spec_shaking_marker); + } +} + +// Additional SDK types +impl SpecShakingMarker for crate::MuxedAddress {} +impl SpecShakingMarker for crate::crypto::Hash {} +impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381G1Affine {} +impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381G2Affine {} +impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381Fp {} +impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381Fp2 {} +impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381Fr {} +impl SpecShakingMarker for crate::crypto::bn254::Bn254G1Affine {} +impl SpecShakingMarker for crate::crypto::bn254::Bn254G2Affine {} +impl SpecShakingMarker for crate::crypto::bn254::Bn254Fp {} +impl SpecShakingMarker for crate::crypto::bn254::Bn254Fr {} + +// Auth types - these have export=false but are legitimately used at external +// boundaries (as inputs to __check_auth in custom account contracts). +// They don't emit specs themselves because they're internal SDK types. +impl SpecShakingMarker for crate::auth::Context {} +impl SpecShakingMarker for crate::auth::ContractContext {} +impl SpecShakingMarker for crate::auth::CreateContractHostFnContext {} +impl SpecShakingMarker for crate::auth::CreateContractWithConstructorHostFnContext {} +impl SpecShakingMarker for crate::auth::ContractExecutable {} +impl SpecShakingMarker for crate::auth::InvokerContractAuthEntry {} +impl SpecShakingMarker for crate::auth::SubContractInvocation {} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/storage.rs b/temp_sdk/soroban-sdk-26.0.1/src/storage.rs new file mode 100644 index 0000000..c2a2c11 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/storage.rs @@ -0,0 +1,775 @@ +//! Storage contains types for storing data for the currently executing contract. +use core::fmt::Debug; + +use crate::{ + env::internal::{self, ContractTtlExtension, StorageType, Val}, + unwrap::{UnwrapInfallible, UnwrapOptimized}, + Env, IntoVal, TryFromVal, +}; + +/// Storage stores and retrieves data for the currently executing contract. +/// +/// All data stored can only be queried and modified by the contract that stores +/// it. Contracts cannot query or modify data stored by other contracts. +/// +/// There are three types of storage - Temporary, Persistent, and Instance. +/// +/// Temporary entries are the cheaper storage option and are never in the Expired State Stack (ESS). Whenever +/// a TemporaryEntry expires, the entry is permanently deleted and cannot be recovered. +/// This storage type is best for entries that are only relevant for short periods of +/// time or for entries that can be arbitrarily recreated. +/// +/// Persistent entries are the more expensive storage type. Whenever +/// a persistent entry expires, it is deleted from the ledger, sent to the ESS +/// and can be recovered via an operation in Stellar Core. Only a single version of a +/// persistent entry can exist at a time. +/// +/// Instance storage is used to store entries within the Persistent contract +/// instance entry, allowing users to tie that data directly to the TTL +/// of the instance. Instance storage is good for global contract data like +/// metadata, admin accounts, or pool reserves. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{Env, Symbol}; +/// +/// # use soroban_sdk::{contract, contractimpl, symbol_short, BytesN}; +/// # +/// # #[contract] +/// # pub struct Contract; +/// # +/// # #[contractimpl] +/// # impl Contract { +/// # pub fn f(env: Env) { +/// let storage = env.storage(); +/// let key = symbol_short!("key"); +/// storage.persistent().set(&key, &1); +/// assert_eq!(storage.persistent().has(&key), true); +/// assert_eq!(storage.persistent().get::<_, i32>(&key), Some(1)); +/// # } +/// # } +/// # +/// # #[cfg(feature = "testutils")] +/// # fn main() { +/// # let env = Env::default(); +/// # let contract_id = env.register(Contract, ()); +/// # ContractClient::new(&env, &contract_id).f(); +/// # } +/// # #[cfg(not(feature = "testutils"))] +/// # fn main() { } +/// ``` +#[derive(Clone)] +pub struct Storage { + env: Env, +} + +impl Debug for Storage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Storage") + } +} + +impl Storage { + #[inline(always)] + pub(crate) fn new(env: &Env) -> Storage { + Storage { env: env.clone() } + } + + /// Storage for data that can stay in the ledger forever until deleted. + /// + /// Persistent entries might expire and be removed from the ledger if they run out + /// of the rent balance. However, expired entries can be restored and + /// they cannot be recreated. This means these entries + /// behave 'as if' they were stored in the ledger forever. + /// + /// This should be used for data that requires persistency, such as token + /// balances, user properties etc. + pub fn persistent(&self) -> Persistent { + debug_assert_in_contract!(self.env); + + Persistent { + storage: self.clone(), + } + } + + /// Storage for data that may stay in ledger only for a limited amount of + /// time. + /// + /// Temporary storage is cheaper than Persistent storage. + /// + /// Temporary entries will be removed from the ledger after their lifetime + /// ends. Removed entries can be created again, potentially with different + /// values. + /// + /// This should be used for data that needs to only exist for a limited + /// period of time, such as oracle data, claimable balances, offer, etc. + pub fn temporary(&self) -> Temporary { + debug_assert_in_contract!(self.env); + + Temporary { + storage: self.clone(), + } + } + + /// Storage for a **small amount** of persistent data associated with + /// the current contract's instance. + /// + /// Storing a small amount of frequently used data in instance storage is + /// likely cheaper than storing it separately in Persistent storage. + /// + /// Instance storage is tightly coupled with the contract instance: it will + /// be loaded from the ledger every time the contract instance itself is + /// loaded. It also won't appear in the ledger footprint. *All* + /// the data stored in the instance storage is read from ledger every time + /// the contract is used and it doesn't matter whether contract uses the + /// storage or not. + /// + /// This has the same lifetime properties as Persistent storage, i.e. + /// the data semantically stays in the ledger forever and can be + /// expired/restored. + /// + /// The amount of data that can be stored in the instance storage is limited + /// by the ledger entry size (a network-defined parameter). It is + /// in the order of 100 KB serialized. + /// + /// This should be used for small data directly associated with the current + /// contract, such as its admin, configuration settings, tokens the contract + /// operates on etc. Do not use this with any data that can scale in + /// unbounded fashion (such as user balances). + pub fn instance(&self) -> Instance { + debug_assert_in_contract!(self.env); + + Instance { + storage: self.clone(), + } + } + + /// Returns the maximum time-to-live (TTL) for all the Soroban ledger entries. + /// + /// TTL is the number of ledgers left until the instance entry is considered + /// expired, excluding the current ledger. Maximum TTL represents the maximum + /// possible TTL of an entry and maximum extension via `extend_ttl` methods. + pub fn max_ttl(&self) -> u32 { + let seq = self.env.ledger().sequence(); + let max = self.env.ledger().max_live_until_ledger(); + max.saturating_sub(seq) + } + + /// Returns if there is a value stored for the given key in the currently + /// executing contracts storage. + #[inline(always)] + pub(crate) fn has(&self, key: &K, storage_type: StorageType) -> bool + where + K: IntoVal, + { + self.has_internal(key.into_val(&self.env), storage_type) + } + + /// Returns the value stored for the given key in the currently executing + /// contract's storage, when present. + /// + /// Returns `None` when the value is missing. + /// + /// If the value is present, then the returned value will be a result of + /// converting the internal value representation to `V`, or will panic if + /// the conversion to `V` fails. + #[inline(always)] + pub(crate) fn get(&self, key: &K, storage_type: StorageType) -> Option + where + K: IntoVal, + V: TryFromVal, + { + let key = key.into_val(&self.env); + if self.has_internal(key, storage_type) { + let rv = self.get_internal(key, storage_type); + Some(V::try_from_val(&self.env, &rv).unwrap_optimized()) + } else { + None + } + } + + /// Returns the value there is a value stored for the given key in the + /// currently executing contract's storage. + /// + /// The returned value is a result of converting the internal value + pub(crate) fn set(&self, key: &K, val: &V, storage_type: StorageType) + where + K: IntoVal, + V: IntoVal, + { + let env = &self.env; + internal::Env::put_contract_data(env, key.into_val(env), val.into_val(env), storage_type) + .unwrap_infallible(); + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. + /// + /// The returned value is the value stored after updating. + pub(crate) fn update( + &self, + key: &K, + storage_type: StorageType, + f: impl FnOnce(Option) -> V, + ) -> V + where + K: IntoVal, + V: TryFromVal, + V: IntoVal, + { + let key = key.into_val(&self.env); + let val = self.get(&key, storage_type); + let val = f(val); + self.set(&key, &val, storage_type); + val + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. If the function returns an error it + /// will be passed through. + /// + /// The returned value is the value stored after updating. + pub(crate) fn try_update( + &self, + key: &K, + storage_type: StorageType, + f: impl FnOnce(Option) -> Result, + ) -> Result + where + K: IntoVal, + V: TryFromVal, + V: IntoVal, + { + let key = key.into_val(&self.env); + let val = self.get(&key, storage_type); + let val = f(val)?; + self.set(&key, &val, storage_type); + Ok(val) + } + + pub(crate) fn extend_ttl( + &self, + key: &K, + storage_type: StorageType, + threshold: u32, + extend_to: u32, + ) where + K: IntoVal, + { + let env = &self.env; + internal::Env::extend_contract_data_ttl( + env, + key.into_val(env), + storage_type, + threshold.into(), + extend_to.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the data with limits on the extension. + /// + /// Extends the TTL of the data to be up to `extend_to` ledgers. The extension + /// only happens if it exceeds `min_extension` ledgers, otherwise this is a no-op. + /// The amount of extension will not exceed `max_extension` ledgers. + /// + /// The TTL is the number of ledgers between the current ledger and the final + /// ledger the data can still be accessed. + pub(crate) fn extend_ttl_with_limits( + &self, + key: &K, + storage_type: StorageType, + extend_to: u32, + min_extension: u32, + max_extension: u32, + ) where + K: IntoVal, + { + let env = &self.env; + internal::Env::extend_contract_data_ttl_v2( + env, + key.into_val(env), + storage_type, + extend_to.into(), + min_extension.into(), + max_extension.into(), + ) + .unwrap_infallible(); + } + + /// Removes the key and the corresponding value from the currently executing + /// contract's storage. + /// + /// No-op if the key does not exist. + #[inline(always)] + pub(crate) fn remove(&self, key: &K, storage_type: StorageType) + where + K: IntoVal, + { + let env = &self.env; + internal::Env::del_contract_data(env, key.into_val(env), storage_type).unwrap_infallible(); + } + + fn has_internal(&self, key: Val, storage_type: StorageType) -> bool { + internal::Env::has_contract_data(&self.env, key, storage_type) + .unwrap_infallible() + .into() + } + + fn get_internal(&self, key: Val, storage_type: StorageType) -> Val { + internal::Env::get_contract_data(&self.env, key, storage_type).unwrap_infallible() + } +} + +pub struct Persistent { + storage: Storage, +} + +impl Persistent { + pub fn has(&self, key: &K) -> bool + where + K: IntoVal, + { + self.storage.has(key, StorageType::Persistent) + } + + pub fn get(&self, key: &K) -> Option + where + V::Error: Debug, + K: IntoVal, + V: TryFromVal, + { + self.storage.get(key, StorageType::Persistent) + } + + pub fn set(&self, key: &K, val: &V) + where + K: IntoVal, + V: IntoVal, + { + self.storage.set(key, val, StorageType::Persistent) + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. + /// + /// The returned value is the value stored after updating. + pub fn update(&self, key: &K, f: impl FnOnce(Option) -> V) -> V + where + K: IntoVal, + V: IntoVal, + V: TryFromVal, + { + self.storage.update(key, StorageType::Persistent, f) + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. If the function returns an error it + /// will be passed through. + /// + /// The returned value is the value stored after updating. + pub fn try_update( + &self, + key: &K, + f: impl FnOnce(Option) -> Result, + ) -> Result + where + K: IntoVal, + V: IntoVal, + V: TryFromVal, + { + self.storage.try_update(key, StorageType::Persistent, f) + } + + /// Extend the TTL of the data under the key. + /// + /// Extends the TTL only if the TTL for the provided data is below `threshold` ledgers. + /// The TTL will then become `extend_to`. + /// + /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. + pub fn extend_ttl(&self, key: &K, threshold: u32, extend_to: u32) + where + K: IntoVal, + { + self.storage + .extend_ttl(key, StorageType::Persistent, threshold, extend_to) + } + + /// Extend the TTL of the data under the key with limits on the extension. + /// + /// Extends the TTL of the data to be up to `extend_to` ledgers. The extension + /// only happens if it exceeds `min_extension` ledgers, otherwise this is a no-op. + /// The amount of extension will not exceed `max_extension` ledgers. + /// + /// The TTL is the number of ledgers between the current ledger and the final + /// ledger the data can still be accessed. + pub fn extend_ttl_with_limits( + &self, + key: &K, + extend_to: u32, + min_extension: u32, + max_extension: u32, + ) where + K: IntoVal, + { + self.storage.extend_ttl_with_limits( + key, + StorageType::Persistent, + extend_to, + min_extension, + max_extension, + ) + } + + #[inline(always)] + pub fn remove(&self, key: &K) + where + K: IntoVal, + { + self.storage.remove(key, StorageType::Persistent) + } +} + +pub struct Temporary { + storage: Storage, +} + +impl Temporary { + pub fn has(&self, key: &K) -> bool + where + K: IntoVal, + { + self.storage.has(key, StorageType::Temporary) + } + + pub fn get(&self, key: &K) -> Option + where + V::Error: Debug, + K: IntoVal, + V: TryFromVal, + { + self.storage.get(key, StorageType::Temporary) + } + + pub fn set(&self, key: &K, val: &V) + where + K: IntoVal, + V: IntoVal, + { + self.storage.set(key, val, StorageType::Temporary) + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. + /// + /// The returned value is the value stored after updating. + pub fn update(&self, key: &K, f: impl FnOnce(Option) -> V) -> V + where + K: IntoVal, + V: IntoVal, + V: TryFromVal, + { + self.storage.update(key, StorageType::Temporary, f) + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. If the function returns an error it + /// will be passed through. + /// + /// The returned value is the value stored after updating. + pub fn try_update( + &self, + key: &K, + f: impl FnOnce(Option) -> Result, + ) -> Result + where + K: IntoVal, + V: IntoVal, + V: TryFromVal, + { + self.storage.try_update(key, StorageType::Temporary, f) + } + + /// Extend the TTL of the data under the key. + /// + /// Extends the TTL only if the TTL for the provided data is below `threshold` ledgers. + /// The TTL will then become `extend_to`. + /// + /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. + pub fn extend_ttl(&self, key: &K, threshold: u32, extend_to: u32) + where + K: IntoVal, + { + self.storage + .extend_ttl(key, StorageType::Temporary, threshold, extend_to) + } + + #[inline(always)] + pub fn remove(&self, key: &K) + where + K: IntoVal, + { + self.storage.remove(key, StorageType::Temporary) + } +} + +pub struct Instance { + storage: Storage, +} + +impl Instance { + pub fn has(&self, key: &K) -> bool + where + K: IntoVal, + { + self.storage.has(key, StorageType::Instance) + } + + pub fn get(&self, key: &K) -> Option + where + V::Error: Debug, + K: IntoVal, + V: TryFromVal, + { + self.storage.get(key, StorageType::Instance) + } + + pub fn set(&self, key: &K, val: &V) + where + K: IntoVal, + V: IntoVal, + { + self.storage.set(key, val, StorageType::Instance) + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. + /// + /// The returned value is the value stored after updating. + pub fn update(&self, key: &K, f: impl FnOnce(Option) -> V) -> V + where + K: IntoVal, + V: IntoVal, + V: TryFromVal, + { + self.storage.update(key, StorageType::Instance, f) + } + + /// Update a value stored against a key. + /// + /// Loads the value, calls the function with it, then sets the value to the + /// returned value of the function. If no value is stored with the key then + /// the function is called with None. If the function returns an error it + /// will be passed through. + /// + /// The returned value is the value stored after updating. + pub fn try_update( + &self, + key: &K, + f: impl FnOnce(Option) -> Result, + ) -> Result + where + K: IntoVal, + V: IntoVal, + V: TryFromVal, + { + self.storage.try_update(key, StorageType::Instance, f) + } + + #[inline(always)] + pub fn remove(&self, key: &K) + where + K: IntoVal, + { + self.storage.remove(key, StorageType::Instance) + } + + /// Extend the TTL of the contract instance and code. + /// + /// Extends the TTL of the instance and code only if the TTL for the provided contract is below `threshold` ledgers. + /// The TTL will then become `extend_to`. Note that the `threshold` check and TTL extensions are done for both the + /// contract code and contract instance, so it's possible that one is bumped but not the other depending on what the + /// current TTL's are. + /// + /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. + pub fn extend_ttl(&self, threshold: u32, extend_to: u32) { + internal::Env::extend_current_contract_instance_and_code_ttl( + &self.storage.env, + threshold.into(), + extend_to.into(), + ) + .unwrap_infallible(); + } + + /// Extend the TTL of the contract instance and code with limits on the extension. + /// + /// Extends the TTL of the instance and code to be up to `extend_to` ledgers. + /// The extension only happens if it exceeds `min_extension` ledgers, otherwise + /// this is a no-op. The amount of extension will not exceed `max_extension` ledgers. + /// + /// Note that the extension is applied to both the contract code and contract instance, + /// so it's possible that one is extended but not the other depending on their current TTLs. + /// + /// The TTL is the number of ledgers between the current ledger and the final ledger + /// the data can still be accessed. + pub fn extend_ttl_with_limits(&self, extend_to: u32, min_extension: u32, max_extension: u32) { + internal::Env::extend_contract_instance_and_code_ttl_v2( + &self.storage.env, + self.storage.env.current_contract_address().to_object(), + ContractTtlExtension::InstanceAndCode, + extend_to.into(), + min_extension.into(), + max_extension.into(), + ) + .unwrap_infallible(); + } +} + +#[cfg(any(test, feature = "testutils"))] +#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] +mod testutils { + use super::*; + use crate::{testutils, xdr, Map, TryIntoVal}; + + impl testutils::storage::Instance for Instance { + fn all(&self) -> Map { + let env = &self.storage.env; + let storage = env.host().get_stored_entries().unwrap(); + let address: xdr::ScAddress = env.current_contract_address().try_into().unwrap(); + for entry in storage { + let (k, Some((v, _))) = entry else { + continue; + }; + let xdr::LedgerKey::ContractData(xdr::LedgerKeyContractData { + ref contract, .. + }) = *k + else { + continue; + }; + if contract != &address { + continue; + } + let xdr::LedgerEntry { + data: + xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry { + key: xdr::ScVal::LedgerKeyContractInstance, + val: + xdr::ScVal::ContractInstance(xdr::ScContractInstance { + ref storage, + .. + }), + .. + }), + .. + } = *v + else { + continue; + }; + return match storage { + Some(map) => { + let map: Val = + Val::try_from_val(env, &xdr::ScVal::Map(Some(map.clone()))).unwrap(); + map.try_into_val(env).unwrap() + } + None => Map::new(env), + }; + } + panic!("contract instance for current contract address not found"); + } + + fn get_ttl(&self) -> u32 { + let env = &self.storage.env; + env.host() + .get_contract_instance_live_until_ledger(env.current_contract_address().to_object()) + .unwrap() + .checked_sub(env.ledger().sequence()) + .unwrap() + } + } + + impl testutils::storage::Persistent for Persistent { + fn all(&self) -> Map { + all(&self.storage.env, xdr::ContractDataDurability::Persistent) + } + + fn get_ttl>(&self, key: &K) -> u32 { + let env = &self.storage.env; + env.host() + .get_contract_data_live_until_ledger(key.into_val(env), StorageType::Persistent) + .unwrap() + .checked_sub(env.ledger().sequence()) + .unwrap() + } + } + + impl testutils::storage::Temporary for Temporary { + fn all(&self) -> Map { + all(&self.storage.env, xdr::ContractDataDurability::Temporary) + } + + fn get_ttl>(&self, key: &K) -> u32 { + let env = &self.storage.env; + env.host() + .get_contract_data_live_until_ledger(key.into_val(env), StorageType::Temporary) + .unwrap() + .checked_sub(env.ledger().sequence()) + .unwrap() + } + } + + fn all(env: &Env, d: xdr::ContractDataDurability) -> Map { + let storage = env.host().get_stored_entries().unwrap(); + let mut map = Map::::new(env); + for entry in storage { + let (_, Some((v, _))) = entry else { + continue; + }; + let xdr::LedgerEntry { + data: + xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry { + ref key, + ref val, + durability, + .. + }), + .. + } = *v + else { + continue; + }; + if d != durability { + continue; + } + let Ok(key) = Val::try_from_val(env, key) else { + continue; + }; + let Ok(val) = Val::try_from_val(env, val) else { + continue; + }; + map.set(key, val); + } + map + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/string.rs b/temp_sdk/soroban-sdk-26.0.1/src/string.rs new file mode 100644 index 0000000..e4382a6 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/string.rs @@ -0,0 +1,417 @@ +use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; + +use super::{ + env::internal::{Env as _, EnvBase as _, StringObject}, + Bytes, ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, +}; + +use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; +#[cfg(doc)] +use crate::{storage::Storage, Map, Vec}; + +#[cfg(not(target_family = "wasm"))] +use super::xdr::{ScString, ScVal}; + +/// String is a contiguous growable array type containing `u8`s. +/// +/// The array is stored in the Host and available to the Guest through the +/// functions defined on String. +/// +/// String values can be stored as [Storage], or in other types like [Vec], +/// [Map], etc. +/// +/// ### Examples +/// +/// String values can be created from slices: +/// ``` +/// use soroban_sdk::{String, Env}; +/// +/// let env = Env::default(); +/// let msg = "a message"; +/// let s = String::from_str(&env, msg); +/// let mut out = [0u8; 9]; +/// s.copy_into_slice(&mut out); +/// assert_eq!(msg.as_bytes(), out) +/// ``` +#[derive(Clone)] +pub struct String { + env: Env, + obj: StringObject, +} + +impl Debug for String { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(target_family = "wasm")] + write!(f, "String(..)")?; + #[cfg(not(target_family = "wasm"))] + write!(f, "String({self})")?; + Ok(()) + } +} + +impl Eq for String {} + +impl PartialEq for String { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for String { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + #[cfg(not(target_family = "wasm"))] + if !self.env.is_same_env(&other.env) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = self + .env + .obj_cmp(self.obj.to_val(), other.obj.to_val()) + .unwrap_infallible(); + v.cmp(&0) + } +} + +impl TryFromVal for String { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &String) -> Result { + Ok(v.clone()) + } +} + +impl TryFromVal for String { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &StringObject) -> Result { + Ok(unsafe { String::unchecked_new(env.clone(), *val) }) + } +} + +impl TryFromVal for String { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(StringObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &String) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&String) -> Result { + Ok(v.to_val()) + } +} + +impl From for Val { + #[inline(always)] + fn from(v: String) -> Self { + v.obj.into() + } +} + +impl From for StringObject { + #[inline(always)] + fn from(v: String) -> Self { + v.obj + } +} + +impl From<&String> for StringObject { + #[inline(always)] + fn from(v: &String) -> Self { + v.obj + } +} + +impl From<&String> for String { + #[inline(always)] + fn from(v: &String) -> Self { + v.clone() + } +} + +impl From<&String> for Bytes { + fn from(v: &String) -> Self { + Env::string_to_bytes(&v.env, v.obj.clone()) + .unwrap_infallible() + .into_val(&v.env) + } +} + +impl From for Bytes { + fn from(v: String) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&String> for ScVal { + fn from(v: &String) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for ScVal { + fn from(v: String) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for String { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok( + StringObject::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible(), + ) + } +} + +impl TryFromVal for String { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &&str) -> Result { + Ok(String::from_str(env, v)) + } +} + +#[cfg(not(target_family = "wasm"))] +impl core::fmt::Display for String { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let sc_val: ScVal = self.try_into().unwrap(); + if let ScVal::String(ScString(s)) = sc_val { + let utf8_s = s.to_utf8_string().unwrap(); + write!(f, "{utf8_s}")?; + } else { + panic!("value is not a string"); + } + Ok(()) + } +} + +impl String { + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: StringObject) -> Self { + Self { env, obj } + } + + #[inline(always)] + pub fn env(&self) -> &Env { + &self.env + } + + pub fn as_val(&self) -> &Val { + self.obj.as_val() + } + + pub fn to_val(&self) -> Val { + self.obj.to_val() + } + + pub fn as_object(&self) -> &StringObject { + &self.obj + } + + pub fn to_object(&self) -> StringObject { + self.obj + } + + #[inline(always)] + #[doc(hidden)] + #[deprecated(note = "use from_str")] + pub fn from_slice(env: &Env, slice: &str) -> String { + Self::from_str(env, slice) + } + + #[inline(always)] + pub fn from_bytes(env: &Env, b: &[u8]) -> String { + String { + env: env.clone(), + obj: env.string_new_from_slice(b).unwrap_optimized(), + } + } + + #[inline(always)] + pub fn from_str(env: &Env, s: &str) -> String { + String { + env: env.clone(), + obj: env.string_new_from_slice(s.as_bytes()).unwrap_optimized(), + } + } + + #[inline(always)] + pub fn len(&self) -> u32 { + self.env().string_len(self.obj).unwrap_infallible().into() + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Copy the bytes in [String] into the given slice. + /// + /// ### Panics + /// + /// If the output slice and string are of different lengths. + #[inline(always)] + pub fn copy_into_slice(&self, slice: &mut [u8]) { + let env = self.env(); + if self.len() as usize != slice.len() { + sdk_panic!("String::copy_into_slice with mismatched slice length") + } + env.string_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) + .unwrap_optimized(); + } + + /// Converts the contents of the String into a respective Bytes object. + pub fn to_bytes(&self) -> Bytes { + self.into() + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::IntoVal; + + #[test] + fn string_from_and_to_slices() { + let env = Env::default(); + + let msg = "a message"; + let s = String::from_str(&env, msg); + let mut out = [0u8; 9]; + s.copy_into_slice(&mut out); + assert_eq!(msg.as_bytes(), out) + } + + #[test] + fn string_from_and_to_bytes() { + let env = Env::default(); + + let msg = b"a message"; + let s = String::from_bytes(&env, msg); + let mut out = [0u8; 9]; + s.copy_into_slice(&mut out); + assert_eq!(msg, &out) + } + + #[test] + #[should_panic] + fn string_to_short_slice() { + let env = Env::default(); + let msg = "a message"; + let s = String::from_str(&env, msg); + let mut out = [0u8; 8]; + s.copy_into_slice(&mut out); + } + + #[test] + #[should_panic] + fn string_to_long_slice() { + let env = Env::default(); + let msg = "a message"; + let s = String::from_str(&env, msg); + let mut out = [0u8; 10]; + s.copy_into_slice(&mut out); + } + + #[test] + fn string_to_val() { + let env = Env::default(); + + let s = String::from_str(&env, "abcdef"); + let val: Val = s.clone().into_val(&env); + let rt: String = val.into_val(&env); + + assert_eq!(s, rt); + } + + #[test] + fn ref_string_to_val() { + let env = Env::default(); + + let s = String::from_str(&env, "abcdef"); + let val: Val = (&s).into_val(&env); + let rt: String = val.into_val(&env); + + assert_eq!(s, rt); + } + + #[test] + fn double_ref_string_to_val() { + let env = Env::default(); + + let s = String::from_str(&env, "abcdef"); + let val: Val = (&&s).into_val(&env); + let rt: String = val.into_val(&env); + + assert_eq!(s, rt); + } + + #[test] + fn test_string_to_bytes() { + let env = Env::default(); + let s = String::from_str(&env, "abcdef"); + let b: Bytes = s.clone().into(); + assert_eq!(b.len(), 6); + let mut slice = [0u8; 6]; + b.copy_into_slice(&mut slice); + assert_eq!(&slice, b"abcdef"); + let b2 = s.to_bytes(); + assert_eq!(b, b2); + } + + #[test] + fn test_string_accepts_any_bytes_even_invalid_utf8() { + let env = Env::default(); + let input = b"a\xc3\x28d"; // \xc3 is invalid utf8 + let s = String::from_bytes(&env, &input[..]); + let b = s.to_bytes().to_buffer::<4>(); + assert_eq!(b.as_slice(), input); + } + + #[test] + fn test_string_display_to_string() { + let env = Env::default(); + let input = "abcdef"; + let s = String::from_str(&env, input); + let rt = s.to_string(); + assert_eq!(input, &rt); + } + + #[test] + #[should_panic = "Utf8Error"] + fn test_string_display_to_string_invalid_utf8() { + let env = Env::default(); + let input = b"a\xc3\x28d"; // \xc3 is invalid utf8 + let s = String::from_bytes(&env, &input[..]); + let _ = s.to_string(); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/symbol.rs b/temp_sdk/soroban-sdk-26.0.1/src/symbol.rs new file mode 100644 index 0000000..2dfbb34 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/symbol.rs @@ -0,0 +1,299 @@ +use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; + +use super::{ + env::internal::{Env as _, Symbol as SymbolVal, SymbolSmall}, + ConversionError, Env, TryFromVal, TryIntoVal, Val, +}; + +#[cfg(not(target_family = "wasm"))] +use super::env::SymbolStr; + +#[cfg(not(target_family = "wasm"))] +use crate::env::internal::xdr::{ScSymbol, ScVal}; +use crate::{ + env::MaybeEnv, + unwrap::{UnwrapInfallible, UnwrapOptimized}, +}; + +/// Symbol is a short string with a limited character set. +/// +/// Valid characters are `a-zA-Z0-9_` and maximum length is 32 characters. +/// +/// Symbols are used for the for symbolic identifiers, such as function +/// names and user-defined structure field/enum variant names. That's why +/// these idenfiers have limited length. +/// +/// While Symbols up to 32 characters long are allowed, Symbols that are 9 +/// characters long or shorter are more efficient at runtime and also can be +/// computed at compile time. +#[derive(Clone)] +pub struct Symbol { + env: MaybeEnv, + val: SymbolVal, +} + +impl Debug for Symbol { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #[cfg(target_family = "wasm")] + write!(f, "Symbol(..)")?; + #[cfg(not(target_family = "wasm"))] + write!(f, "Symbol({})", self.to_string())?; + Ok(()) + } +} + +impl Eq for Symbol {} + +impl PartialEq for Symbol { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for Symbol { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Symbol { + fn cmp(&self, other: &Self) -> Ordering { + let self_raw = self.val.to_val(); + let other_raw = other.val.to_val(); + + match ( + SymbolSmall::try_from(self_raw), + SymbolSmall::try_from(other_raw), + ) { + // Compare small symbols. + (Ok(self_sym), Ok(other_sym)) => self_sym.cmp(&other_sym), + // The object-to-small symbol comparisons are handled by `obj_cmp`, + // so it's safe to handle all the other cases using it. + _ => { + let (e1, e2): (Result, Result) = + (self.env.clone().try_into(), other.env.clone().try_into()); + match (e1, e2) { + (Err(_), Err(_)) => { + panic!("symbol object is missing the env reference"); + } + (Err(_), Ok(e)) | (Ok(e), Err(_)) => { + let v = e.obj_cmp(self_raw, other_raw).unwrap_infallible(); + v.cmp(&0) + } + #[cfg(not(target_family = "wasm"))] + (Ok(e1), Ok(e2)) => { + if !e1.is_same_env(&e2) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = e1.obj_cmp(self_raw, other_raw).unwrap_infallible(); + v.cmp(&0) + } + #[cfg(target_family = "wasm")] + (Ok(e), Ok(_)) => { + let v = e.obj_cmp(self_raw, other_raw).unwrap_infallible(); + v.cmp(&0) + } + } + } + } + } +} + +impl TryFromVal for Symbol { + type Error = Infallible; + + fn try_from_val(env: &Env, val: &SymbolVal) -> Result { + Ok(unsafe { Symbol::unchecked_new(env.clone(), *val) }) + } +} + +impl TryFromVal for Symbol { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(SymbolVal::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &Symbol) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&Symbol) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal for Symbol { + type Error = ConversionError; + + fn try_from_val(env: &Env, val: &&str) -> Result { + Ok(SymbolVal::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Symbol> for ScVal { + fn from(v: &Symbol) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + if let Ok(ss) = SymbolSmall::try_from(v.val) { + ScVal::try_from(ss).unwrap() + } else { + let e: Env = v.env.clone().try_into().unwrap(); + ScVal::try_from_val(&e, &v.to_val()).unwrap() + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl From for ScVal { + fn from(v: Symbol) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for ScVal { + type Error = ConversionError; + fn try_from_val(_e: &Env, v: &Symbol) -> Result { + Ok(v.into()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Symbol { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok(SymbolVal::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Symbol { + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScSymbol) -> Result { + Ok(SymbolVal::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl Symbol { + /// Creates a new Symbol given a string with valid characters. + /// + /// Valid characters are `a-zA-Z0-9_` and maximum string length is 32 + /// characters. + /// + /// Use `symbol_short!` for constant symbols that are 9 characters or less. + /// + /// Use `Symbol::try_from_val(env, s)`/`s.try_into_val(env)` in case if + /// failures need to be handled gracefully. + /// + /// ### Panics + /// + /// When the input string is not representable by Symbol. + pub fn new(env: &Env, s: &str) -> Self { + Self { + env: env.clone().into(), + val: s.try_into_val(env).unwrap_optimized(), + } + } + + /// Creates a new Symbol given a short string with valid characters. + /// + /// Valid characters are `a-zA-Z0-9_` and maximum length is 9 characters. + /// + /// The conversion can happen at compile time if called in a const context, + /// such as: + /// + /// ```rust + /// # use soroban_sdk::Symbol; + /// const SYMBOL: Symbol = Symbol::short("abcde"); + /// ``` + /// + /// Note that when called from a non-const context the conversion will occur + /// at runtime and the conversion logic will add considerable number of + /// bytes to built wasm file. For this reason the function should be generally + /// avoided: + /// + /// ```rust + /// # use soroban_sdk::Symbol; + /// let SYMBOL: Symbol = Symbol::short("abcde"); // AVOID! + /// ``` + /// + /// Instead use the `symbol_short!()` macro that will ensure the conversion always occurs in a const-context: + /// + /// ```rust + /// # use soroban_sdk::{symbol_short, Symbol}; + /// let SYMBOL: Symbol = symbol_short!("abcde"); // 👍 + /// ``` + /// + /// ### Panics + /// + /// When the input string is not representable by Symbol. + #[doc(hidden)] + #[deprecated(note = "use [symbol_short!()]")] + pub const fn short(s: &str) -> Self { + if let Ok(sym) = SymbolSmall::try_from_str(s) { + Symbol { + env: MaybeEnv::none(), + val: SymbolVal::from_small(sym), + } + } else { + panic!("short symbols are limited to 9 characters"); + } + } + + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, val: SymbolVal) -> Self { + Self { + env: env.into(), + val, + } + } + + pub fn as_val(&self) -> &Val { + self.val.as_val() + } + + pub fn to_val(&self) -> Val { + self.val.to_val() + } + + pub fn to_symbol_val(&self) -> SymbolVal { + self.val + } +} + +#[cfg(not(target_family = "wasm"))] +extern crate std; +#[cfg(not(target_family = "wasm"))] +impl ToString for Symbol { + fn to_string(&self) -> String { + if let Ok(s) = SymbolSmall::try_from(self.val) { + s.to_string() + } else { + let e: Env = self.env.clone().try_into().unwrap_optimized(); + SymbolStr::try_from_val(&e, &self.val) + .unwrap_optimized() + .to_string() + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/tests.rs b/temp_sdk/soroban-sdk-26.0.1/src/tests.rs new file mode 100644 index 0000000..6783954 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/tests.rs @@ -0,0 +1,55 @@ +#![cfg(test)] + +mod address; +mod address_payload; +mod auth; +mod bytes_alloc_vec; +mod bytes_buffer; +mod bytes_slice; +mod bytesn; +mod cmp_across_env_in_tests; +mod contract_add_i32; +mod contract_assert; +mod contract_custom_account_impl; +mod contract_docs; +mod contract_duration; +mod contract_event; +mod contract_fn; +mod contract_invoke; +mod contract_invoke_arg_count; +mod contract_meta; +mod contract_overlapping_type_fn_names; +mod contract_snapshot; +mod contract_store; +mod contract_timepoint; +mod contract_udt_enum; +mod contract_udt_enum_error; +mod contract_udt_enum_int; +mod contract_udt_enum_option; +mod contract_udt_option; +mod contract_udt_raw_identifier; +mod contract_udt_struct; +mod contract_udt_struct_tuple; +mod contractimpl_trait_call_resolution; +mod contractimport; +mod contractimport_with_error; +mod cost_estimate; +mod crypto_bls12_381; +mod crypto_bn254; +mod crypto_ed25519; +mod crypto_keccak256; +mod crypto_poseidon; +mod crypto_secp256k1; +mod crypto_secp256r1; +mod crypto_sha256; +mod env; +mod max_ttl; +mod muxed_address; +mod num_checked_arith; +mod prng; +mod prng_range; +mod proptest_scval_cmp; +mod proptest_val_cmp; +mod storage_testutils; +mod token_client; +mod vec_slice; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils.rs new file mode 100644 index 0000000..2580fcf --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/testutils.rs @@ -0,0 +1,798 @@ +#![cfg(any(test, feature = "testutils"))] +#![cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] + +//! Utilities intended for use when testing. + +pub mod arbitrary; + +mod sign; +use std::{fmt::Debug, rc::Rc}; + +pub use sign::ed25519; + +mod mock_auth; +pub use mock_auth::{ + AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthContract, MockAuthInvoke, +}; +use soroban_env_host::{TryFromVal, TryIntoVal}; + +pub mod storage; + +pub mod cost_estimate; + +use crate::{xdr, ConstructorArgs, Env, Val, Vec}; +use soroban_ledger_snapshot::LedgerSnapshot; + +pub use crate::env::EnvTestConfig; + +/// Trait for providing ledger data to the test environment. +/// +/// Implement this trait to create custom snapshot sources that load ledger state +/// from sources other than [`LedgerSnapshot`] files, such as RPC endpoints, +/// history archives, or in-memory data structures. +/// +/// Use with [`SnapshotSourceInput`] and [`Env::from_ledger_snapshot`] to initialize +/// a test environment from a custom source. +pub use crate::env::internal::storage::SnapshotSource; + +/// Error type returned by [`SnapshotSource::get`]. +/// +/// Required for implementing custom snapshot sources. +pub use crate::env::internal::HostError; + +pub trait Register { + fn register<'i, I, A>(self, env: &Env, id: I, args: A) -> crate::Address + where + I: Into>, + A: ConstructorArgs; +} + +impl Register for C +where + C: ContractFunctionSet + 'static, +{ + fn register<'i, I, A>(self, env: &Env, id: I, args: A) -> crate::Address + where + I: Into>, + A: ConstructorArgs, + { + env.register_contract_with_constructor(id, self, args) + } +} + +impl<'w> Register for &'w [u8] { + fn register<'i, I, A>(self, env: &Env, id: I, args: A) -> crate::Address + where + I: Into>, + A: ConstructorArgs, + { + env.register_contract_wasm_with_constructor(id, self, args) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct Snapshot { + pub generators: Generators, + pub auth: AuthSnapshot, + pub ledger: LedgerSnapshot, + pub events: EventsSnapshot, +} + +impl Snapshot { + // Read in a [`Snapshot`] from a reader. + pub fn read(r: impl std::io::Read) -> Result { + Ok(serde_json::from_reader::<_, Snapshot>(r)?) + } + + // Read in a [`Snapshot`] from a file. + pub fn read_file(p: impl AsRef) -> Result { + let reader = std::io::BufReader::new(std::fs::File::open(p)?); + Self::read(reader) + } + + // Write a [`Snapshot`] to a writer. + pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { + Ok(serde_json::to_writer_pretty(w, self)?) + } + + // Write a [`Snapshot`] to file. + pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { + let p = p.as_ref(); + if let Some(dir) = p.parent() { + if !dir.exists() { + std::fs::create_dir_all(dir)?; + } + } + self.write(std::fs::File::create(p)?) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct EventsSnapshot(pub std::vec::Vec); + +impl EventsSnapshot { + // Read in a [`EventsSnapshot`] from a reader. + pub fn read(r: impl std::io::Read) -> Result { + Ok(serde_json::from_reader::<_, EventsSnapshot>(r)?) + } + + // Read in a [`EventsSnapshot`] from a file. + pub fn read_file(p: impl AsRef) -> Result { + let reader = std::io::BufReader::new(std::fs::File::open(p)?); + Self::read(reader) + } + + // Write a [`EventsSnapshot`] to a writer. + pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { + Ok(serde_json::to_writer_pretty(w, self)?) + } + + // Write a [`EventsSnapshot`] to file. + pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { + let p = p.as_ref(); + if let Some(dir) = p.parent() { + if !dir.exists() { + std::fs::create_dir_all(dir)?; + } + } + self.write(std::fs::File::create(p)?) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct EventSnapshot { + pub event: xdr::ContractEvent, + pub failed_call: bool, +} + +impl From for EventSnapshot { + fn from(v: crate::env::internal::events::HostEvent) -> Self { + Self { + event: v.event, + failed_call: v.failed_call, + } + } +} + +#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct AuthSnapshot( + pub std::vec::Vec>, +); + +impl AuthSnapshot { + // Read in a [`AuthSnapshot`] from a reader. + pub fn read(r: impl std::io::Read) -> Result { + Ok(serde_json::from_reader::<_, AuthSnapshot>(r)?) + } + + // Read in a [`AuthSnapshot`] from a file. + pub fn read_file(p: impl AsRef) -> Result { + let reader = std::io::BufReader::new(std::fs::File::open(p)?); + Self::read(reader) + } + + // Write a [`AuthSnapshot`] to a writer. + pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { + Ok(serde_json::to_writer_pretty(w, self)?) + } + + // Write a [`AuthSnapshot`] to file. + pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { + let p = p.as_ref(); + if let Some(dir) = p.parent() { + if !dir.exists() { + std::fs::create_dir_all(dir)?; + } + } + self.write(std::fs::File::create(p)?) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct Generators { + address: u64, + nonce: i64, + mux_id: u64, +} + +impl Default for Generators { + fn default() -> Generators { + Generators { + address: 0, + nonce: 0, + mux_id: 0, + } + } +} + +impl Generators { + // Read in a [`Generators`] from a reader. + pub fn read(r: impl std::io::Read) -> Result { + Ok(serde_json::from_reader::<_, Generators>(r)?) + } + + // Read in a [`Generators`] from a file. + pub fn read_file(p: impl AsRef) -> Result { + let reader = std::io::BufReader::new(std::fs::File::open(p)?); + Self::read(reader) + } + + // Write a [`Generators`] to a writer. + pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { + Ok(serde_json::to_writer_pretty(w, self)?) + } + + // Write a [`Generators`] to file. + pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { + let p = p.as_ref(); + if let Some(dir) = p.parent() { + if !dir.exists() { + std::fs::create_dir_all(dir)?; + } + } + self.write(std::fs::File::create(p)?) + } +} + +impl Generators { + pub fn address(&mut self) -> [u8; 32] { + self.address = self.address.checked_add(1).unwrap(); + let b: [u8; 8] = self.address.to_be_bytes(); + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b[0], b[1], + b[2], b[3], b[4], b[5], b[6], b[7], + ] + } + + pub fn nonce(&mut self) -> i64 { + self.nonce = self.nonce.checked_add(1).unwrap(); + self.nonce + } + + pub fn mux_id(&mut self) -> u64 { + self.mux_id = self.mux_id.checked_add(1).unwrap(); + self.mux_id + } +} + +#[doc(hidden)] +pub type ContractFunctionF = dyn Send + Sync + Fn(Env, &[Val]) -> Val; +#[doc(hidden)] +pub trait ContractFunctionRegister { + fn register(name: &'static str, func: &'static ContractFunctionF); +} +#[doc(hidden)] +pub trait ContractFunctionSet { + fn call(&self, func: &str, env: Env, args: &[Val]) -> Option; +} + +#[doc(inline)] +pub use crate::env::internal::LedgerInfo; + +/// Returns a default `LedgerInfo` suitable for testing. +pub(crate) fn default_ledger_info() -> LedgerInfo { + LedgerInfo { + protocol_version: 26, + sequence_number: 0, + timestamp: 0, + network_id: [0; 32], + base_reserve: 0, + min_persistent_entry_ttl: 4096, + min_temp_entry_ttl: 16, + max_entry_ttl: 6_312_000, + } +} + +/// Test utilities for [`Ledger`][crate::ledger::Ledger]. +pub trait Ledger { + /// Set ledger info. + fn set(&self, l: LedgerInfo); + + /// Sets the protocol version. + fn set_protocol_version(&self, protocol_version: u32); + + /// Sets the sequence number. + fn set_sequence_number(&self, sequence_number: u32); + + /// Sets the timestamp. + fn set_timestamp(&self, timestamp: u64); + + /// Sets the network ID. + fn set_network_id(&self, network_id: [u8; 32]); + + /// Sets the base reserve. + fn set_base_reserve(&self, base_reserve: u32); + + /// Sets the minimum temporary entry time-to-live. + fn set_min_temp_entry_ttl(&self, min_temp_entry_ttl: u32); + + /// Sets the minimum persistent entry time-to-live. + fn set_min_persistent_entry_ttl(&self, min_persistent_entry_ttl: u32); + + /// Sets the maximum entry time-to-live. + fn set_max_entry_ttl(&self, max_entry_ttl: u32); + + /// Get ledger info. + fn get(&self) -> LedgerInfo; + + /// Modify the ledger info. + fn with_mut(&self, f: F) + where + F: FnMut(&mut LedgerInfo); +} + +pub mod budget { + use core::fmt::{Debug, Display}; + + #[doc(inline)] + use crate::env::internal::budget::CostTracker; + #[doc(inline)] + pub use crate::xdr::ContractCostType; + + /// Budget that tracks the resources consumed for the environment. + /// + /// The budget consists of two cost dimensions: + /// - CPU instructions + /// - Memory + /// + /// Inputs feed into those cost dimensions. + /// + /// Note that all cost dimensions – CPU instructions, memory – and the VM + /// cost type inputs are likely to be underestimated when running Rust code + /// compared to running the WASM equivalent. + /// + /// ### Examples + /// + /// ``` + /// use soroban_sdk::{Env, Symbol}; + /// + /// # #[cfg(feature = "testutils")] + /// # fn main() { + /// # let env = Env::default(); + /// env.cost_estimate().budget().reset_default(); + /// // ... + /// println!("{}", env.cost_estimate().budget()); + /// # } + /// # #[cfg(not(feature = "testutils"))] + /// # fn main() { } + /// ``` + pub struct Budget(pub(crate) crate::env::internal::budget::Budget); + + impl Display for Budget { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + writeln!(f, "{}", self.0) + } + } + + impl Debug for Budget { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + writeln!(f, "{:?}", self.0) + } + } + + impl Budget { + pub(crate) fn new(b: crate::env::internal::budget::Budget) -> Self { + Self(b) + } + + /// Reset the budget. + pub fn reset_default(&mut self) { + self.0.reset_default().unwrap(); + } + + pub fn reset_unlimited(&mut self) { + self.0.reset_unlimited().unwrap(); + } + + pub fn reset_limits(&mut self, cpu: u64, mem: u64) { + self.0.reset_limits(cpu, mem).unwrap(); + } + + pub fn reset_tracker(&mut self) { + self.0.reset_tracker().unwrap(); + } + + /// Returns the CPU instruction cost. + /// + /// Note that CPU instructions are likely to be underestimated when + /// running Rust code compared to running the WASM equivalent. + pub fn cpu_instruction_cost(&self) -> u64 { + self.0.get_cpu_insns_consumed().unwrap() + } + + /// Returns the memory cost. + /// + /// Note that memory is likely to be underestimated when running Rust + /// code compared to running the WASM equivalent. + pub fn memory_bytes_cost(&self) -> u64 { + self.0.get_mem_bytes_consumed().unwrap() + } + + /// Get the cost tracker associated with the cost type. The tracker + /// tracks the cumulative iterations and inputs and derived cpu and + /// memory. If the underlying model is a constant model, then inputs is + /// `None` and only iterations matter. + /// + /// Note that VM cost types are likely to be underestimated when running + /// natively as Rust code inside tests code compared to running the WASM + /// equivalent. + pub fn tracker(&self, cost_type: ContractCostType) -> CostTracker { + self.0.get_tracker(cost_type).unwrap() + } + + /// Print the budget costs and inputs to stdout. + pub fn print(&self) { + println!("{}", self.0); + } + } +} + +#[derive(Clone)] +pub struct ContractEvents { + env: Env, + events: std::vec::Vec, +} + +impl ContractEvents { + pub(crate) fn new(env: &Env, events: std::vec::Vec) -> Self { + ContractEvents { + env: env.clone(), + events, + } + } + + /// Returns the events in their XDR form. + pub fn events(&self) -> &[xdr::ContractEvent] { + &self.events + } + + /// Creates a new ContractEvents struct that only includes events emitted + /// by the provided contract address. + pub fn filter_by_contract(&self, addr: &crate::Address) -> Self { + let contract_id = Some(addr.contract_id()); + let filtered_events = self + .events + .iter() + .filter(|e| e.contract_id == contract_id) + .cloned() + .collect(); + Self::new(&self.env, filtered_events) + } +} + +impl Eq for ContractEvents {} + +impl PartialEq for ContractEvents { + fn eq(&self, other: &ContractEvents) -> bool { + self.events == other.events + } +} + +impl PartialEq> for ContractEvents { + fn eq(&self, other: &std::vec::Vec) -> bool { + self.events == *other + } +} + +impl PartialEq<&[xdr::ContractEvent]> for ContractEvents { + fn eq(&self, other: &&[xdr::ContractEvent]) -> bool { + self.events == *other + } +} + +impl PartialEq<[xdr::ContractEvent; N]> for ContractEvents { + fn eq(&self, other: &[xdr::ContractEvent; N]) -> bool { + self.events == other + } +} + +impl PartialEq, Val)>> for ContractEvents { + fn eq(&self, other: &Vec<(crate::Address, Vec, Val)>) -> bool { + let len = match u32::try_from(self.events.len()) { + Ok(len) => len, + Err(..) => return false, + }; + if len != other.len() { + return false; + } + + for (event, (contract_id, topics, data)) in self.events.iter().zip(other.iter()) { + let data_xdr = match xdr::ScVal::try_from_val(&self.env, &data) { + Ok(data_xdr) => data_xdr, + Err(..) => return false, + }; + let as_xdr = xdr::ContractEvent { + ext: xdr::ExtensionPoint::V0, + type_: xdr::ContractEventType::Contract, + contract_id: Some(contract_id.contract_id()), + body: xdr::ContractEventBody::V0(xdr::ContractEventV0 { + topics: topics.into(), + data: data_xdr, + }), + }; + if event != &as_xdr { + return false; + } + } + true + } +} + +impl Debug for ContractEvents { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.events) + } +} + +/// Test utilities for [`Events`][crate::events::Events]. +pub trait Events { + /// Returns all contract events that have been published by the last contract + /// invocation. If the last contract invocation failed, no events are returned. + /// + /// Events are returned in the order they were published, with the + /// last published event being the last in the list. + /// + /// Returns a [`ContractEvents`] struct that contains: + /// - The test Env + /// - A vector of events emitted by successful contract invocations + fn all(&self) -> ContractEvents; +} + +/// Test utilities for [`Logs`][crate::logs::Logs]. +pub trait Logs { + /// Returns all diagnostic events that have been logged. + fn all(&self) -> std::vec::Vec; + /// Prints all diagnostic events to stdout. + fn print(&self); +} + +/// Test utilities for [`BytesN`][crate::BytesN]. +pub trait BytesN { + // Generate a BytesN filled with random bytes. + // + // The value filled is not cryptographically secure. + fn random(env: &Env) -> crate::BytesN; +} + +/// Generates an array of N random bytes. +/// +/// The value returned is not cryptographically secure. +pub(crate) fn random() -> [u8; N] { + use rand::RngCore; + let mut arr = [0u8; N]; + rand::thread_rng().fill_bytes(&mut arr); + arr +} + +pub trait Address { + /// Generate a new Address. + /// + /// Implementation note: this always builds the contract addresses now. This + /// shouldn't normally matter though, as contracts should be agnostic to + /// the underlying Address value. + fn generate(env: &Env) -> crate::Address; +} + +pub trait MuxedAddress { + /// Create a new MuxedAddress with arbitrary `Address` and id parts. + /// + /// Note, that since currently only accounts can be multiplexed, the + /// underlying `Address` will be an account (not contract) address. + fn generate(env: &Env) -> crate::MuxedAddress; + + /// Returns a new `MuxedAddress` that has the same `Address` part as the + /// provided `address` and the provided multiplexing id. + /// + /// `address` can be either an `Address` or `MuxedAddress` and it has to + /// be an account (non-contract) address. + /// + /// Note on usage: the simplest way to test `MuxedAddress` is to generate + /// an arbitrary valid address with `MuxedAddress::generate`, then + /// `MuxedAddress::new` can be used to alter only the multiplexing id part + /// of that address. + fn new>(address: T, id: u64) -> crate::MuxedAddress; +} + +pub trait Deployer { + /// Gets the TTL of the given contract's instance. + /// + /// TTL is the number of ledgers left until the instance entry is considered + /// expired, excluding the current ledger. + /// + /// Panics if there is no instance corresponding to the provided address, + /// or if the instance has expired. + fn get_contract_instance_ttl(&self, contract: &crate::Address) -> u32; + + /// Gets the TTL of the given contract's Wasm code entry. + /// + /// TTL is the number of ledgers left until the contract code entry + /// is considered expired, excluding the current ledger. + /// + /// Panics if there is no contract instance/code corresponding to + /// the provided address, or if the instance/code has expired. + fn get_contract_code_ttl(&self, contract: &crate::Address) -> u32; +} + +pub use xdr::AccountFlags as IssuerFlags; + +#[derive(Clone)] +pub struct StellarAssetIssuer { + env: Env, + account_id: xdr::AccountId, +} + +impl StellarAssetIssuer { + pub(crate) fn new(env: Env, account_id: xdr::AccountId) -> Self { + Self { env, account_id } + } + + /// Returns the flags for the issuer. + pub fn flags(&self) -> u32 { + let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount { + account_id: self.account_id.clone(), + })); + + let (entry, _) = self.env.host().get_ledger_entry(&k).unwrap().unwrap(); + + match &entry.data { + xdr::LedgerEntryData::Account(e) => e.flags, + _ => panic!("expected account entry but got {:?}", entry.data), + } + } + + /// Adds the flag specified to the existing issuer flags + pub fn set_flag(&self, flag: IssuerFlags) { + self.overwrite_issuer_flags(self.flags() | (flag as u32)) + } + + /// Clears the flag specified from the existing issuer flags + pub fn clear_flag(&self, flag: IssuerFlags) { + self.overwrite_issuer_flags(self.flags() & (!(flag as u32))) + } + + pub fn address(&self) -> crate::Address { + xdr::ScAddress::Account(self.account_id.clone()) + .try_into_val(&self.env.clone()) + .unwrap() + } + + /// Sets the issuer flags field. + /// Each flag is a bit with values corresponding to [xdr::AccountFlags] + /// + /// Use this to test interactions between trustlines/balances and the issuer flags. + fn overwrite_issuer_flags(&self, flags: u32) { + if u64::from(flags) > xdr::MASK_ACCOUNT_FLAGS_V17 { + panic!( + "issuer flags value must be at most {}", + xdr::MASK_ACCOUNT_FLAGS_V17 + ); + } + + let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount { + account_id: self.account_id.clone(), + })); + + let (entry, _) = self.env.host().get_ledger_entry(&k).unwrap().unwrap(); + let mut entry = entry.as_ref().clone(); + + match entry.data { + xdr::LedgerEntryData::Account(ref mut e) => e.flags = flags, + _ => panic!("expected account entry but got {:?}", entry.data), + } + + self.env + .host() + .add_ledger_entry(&k, &Rc::new(entry), None) + .unwrap(); + } +} + +pub struct StellarAssetContract { + address: crate::Address, + issuer: StellarAssetIssuer, + asset: xdr::Asset, +} + +impl StellarAssetContract { + pub(crate) fn new( + address: crate::Address, + issuer: StellarAssetIssuer, + asset: xdr::Asset, + ) -> Self { + Self { + address, + issuer, + asset, + } + } + + pub fn address(&self) -> crate::Address { + self.address.clone() + } + + pub fn issuer(&self) -> StellarAssetIssuer { + self.issuer.clone() + } + + #[doc(hidden)] + pub fn asset(&self) -> xdr::Asset { + self.asset.clone() + } +} + +/// Input for creating an [`Env`] from a custom snapshot source. +/// +/// This struct enables [`Env::from_ledger_snapshot`] to accept custom snapshot +/// source types beyond [`LedgerSnapshot`], providing flexibility for testing +/// scenarios that load ledger state from different sources such as RPC endpoints, +/// history archives, or in-memory data structures. +/// +/// # Fields +/// +/// * `source` - A snapshot source implementing the [`SnapshotSource`] trait. +/// This is used to load ledger entries on demand during test execution. +/// +/// * `ledger_info` - Optional ledger info to initialize the environment with. +/// If `None`, default test ledger info is used. +/// +/// * `snapshot` - Optional [`LedgerSnapshot`] used as the base for capturing +/// state changes. When the test completes, modified entries are written to +/// this snapshot. If `None`, a new empty snapshot is created. +/// +/// # Example +/// +/// ``` +/// use soroban_sdk::testutils::{SnapshotSource, SnapshotSourceInput, HostError}; +/// use soroban_sdk::xdr::{LedgerEntry, LedgerKey}; +/// use soroban_sdk::Env; +/// use std::rc::Rc; +/// +/// struct MyCustomSource; +/// +/// impl SnapshotSource for MyCustomSource { +/// fn get( +/// &self, +/// key: &Rc, +/// ) -> Result, Option)>, HostError> { +/// // Return None for keys not found, or Some((entry, live_until_ledger)) +/// Ok(None) +/// } +/// } +/// +/// let input = SnapshotSourceInput { +/// source: Rc::new(MyCustomSource), +/// ledger_info: None, +/// snapshot: None, +/// }; +/// let env = Env::from_ledger_snapshot(input); +/// ``` +pub struct SnapshotSourceInput { + pub source: Rc, + pub ledger_info: Option, + pub snapshot: Option>, +} + +/// Converts a [`LedgerSnapshot`] into a [`SnapshotSourceInput`]. +/// +/// This conversion maintains backward compatibility with the existing API, +/// allowing [`LedgerSnapshot`] to be used directly with [`Env::from_ledger_snapshot`]. +/// +/// The [`LedgerSnapshot`] is wrapped in an [`Rc`] and used for all three fields: +/// - As the snapshot source for loading ledger entries +/// - To provide the ledger info for the environment +/// - As the base snapshot for capturing state changes +impl From for SnapshotSourceInput { + fn from(s: LedgerSnapshot) -> Self { + let s = Rc::new(s); + Self { + source: s.clone(), + ledger_info: Some(s.ledger_info()), + snapshot: Some(s), + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs new file mode 100644 index 0000000..ea8c695 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs @@ -0,0 +1,2235 @@ +//! Support for fuzzing Soroban contracts with [`cargo-fuzz`]. +//! +//! This module provides a pattern for generating Soroban contract types for the +//! purpose of fuzzing Soroban contracts. It is focused on implementing the +//! [`Arbitrary`] trait that `cargo-fuzz` relies on to feed fuzzers with +//! generated Rust values. +//! +//! [`cargo-fuzz`]: https://github.com/rust-fuzz/cargo-fuzz/ +//! [`Arbitrary`]: ::arbitrary::Arbitrary +//! +//! This module +//! +//! - defines the [`SorobanArbitrary`] trait, +//! - reexports the [`arbitrary`] crate and the [`Arbitrary`] type. +//! +//! This module is only available when the "testutils" Cargo feature is defined. +//! +//! +//! ## About `cargo-fuzz` and `Arbitrary` +//! +//! In its basic operation `cargo-fuzz` fuzz generates raw bytes and feeds them +//! to a program-dependent fuzzer designed to exercise a program, in our case a +//! Soroban contract. +//! +//! `cargo-fuzz` programs declare their entry points with a macro: +//! +//! ``` +//! # macro_rules! fuzz_target { +//! # (|$data:ident: $dty: ty| $body:block) => { }; +//! # } +//! fuzz_target!(|input: &[u8]| { +//! // feed bytes to the program +//! }); +//! ``` +//! +//! More sophisticated fuzzers accept not bytes but Rust types: +//! +//! ``` +//! # use arbitrary::Arbitrary; +//! # macro_rules! fuzz_target { +//! # (|$data:ident: $dty: ty| $body:block) => { }; +//! # } +//! #[derive(Arbitrary, Debug)] +//! struct FuzzDeposit { +//! deposit_amount: i128, +//! } +//! +//! fuzz_target!(|input: FuzzDeposit| { +//! // fuzz the program based on the input +//! }); +//! ``` +//! +//! Types accepted as input to `fuzz_target` must implement the `Arbitrary` trait, +//! which transforms bytes to Rust types. +//! +//! +//! ## The `SorobanArbitrary` trait +//! +//! Soroban types are managed by the host environment, and so must be created +//! from an [`Env`] value; `Arbitrary` values though must be created from +//! nothing but bytes. The [`SorobanArbitrary`] trait, implemented for all +//! Soroban contract types, exists to bridge this gap: it defines a _prototype_ +//! pattern whereby the `fuzz_target` macro creates prototype values that the +//! fuzz program can convert to contract values with the standard soroban +//! conversion traits, [`FromVal`] or [`IntoVal`]. +//! +//! [`Env`]: crate::Env +//! [`FromVal`]: crate::FromVal +//! [`IntoVal`]: crate::IntoVal +//! +//! The types of prototypes are identified by the associated type, +//! [`SorobanArbitrary::Prototype`]: +//! +//! ``` +//! # use soroban_sdk::testutils::arbitrary::Arbitrary; +//! # use soroban_sdk::{TryFromVal, IntoVal, Val, Env}; +//! pub trait SorobanArbitrary: +//! TryFromVal + IntoVal + TryFromVal +//! { +//! type Prototype: for <'a> Arbitrary<'a>; +//! } +//! ``` +//! +//! Types that implement `SorobanArbitrary` include: +//! +//! - `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `I256`, `U256`, `()`, and `bool`, +//! - [`Error`], +//! - [`Bytes`], [`BytesN`], [`Vec`], [`Map`], +//! - [`Address`], [`Symbol`], +//! - [`Val`], +//! +//! [`I256`]: crate::I256 +//! [`U256`]: crate::U256 +//! [`Error`]: crate::Error +//! [`Bytes`]: crate::Bytes +//! [`BytesN`]: crate::BytesN +//! [`Vec`]: crate::Vec +//! [`Map`]: crate::Map +//! [`Address`]: crate::Address +//! [`Symbol`]: crate::Symbol +//! [`Val`]: crate::Val +//! +//! All user-defined contract types, those with the [`contracttype`] attribute, +//! automatically derive `SorobanArbitrary`. Note that `SorobanArbitrary` is +//! only derived when the "testutils" Cargo feature is active. This implies +//! that, in general, to make a Soroban contract fuzzable, the contract crate +//! must define a "testutils" Cargo feature, that feature should turn on the +//! "soroban-sdk/testutils" feature, and the fuzz test, which is its own crate, +//! must turn that feature on. +//! +//! [`contracttype`]: crate::contracttype +//! +//! +//! ## Example: take a Soroban `Vec` of `Address` as fuzzer input +//! +//! ``` +//! # macro_rules! fuzz_target { +//! # (|$data:ident: $dty: ty| $body:block) => { }; +//! # } +//! use soroban_sdk::{Address, Env, Vec}; +//! use soroban_sdk::testutils::arbitrary::SorobanArbitrary; +//! +//! fuzz_target!(|input: as SorobanArbitrary>::Prototype| { +//! let env = Env::default(); +//! let addresses: Vec
= input.into_val(&env); +//! // fuzz the program based on the input +//! }); +//! ``` +//! +//! +//! ## Example: take a custom contract type as fuzzer input +//! +//! ``` +//! # macro_rules! fuzz_target { +//! # (|$data:ident: $dty: ty| $body:block) => { }; +//! # } +//! use soroban_sdk::{Address, Env, Vec}; +//! use soroban_sdk::contracttype; +//! use soroban_sdk::testutils::arbitrary::{Arbitrary, SorobanArbitrary}; +//! use std::vec::Vec as RustVec; +//! +//! #[derive(Arbitrary, Debug)] +//! struct TestInput { +//! deposit_amount: i128, +//! claim_address:
::Prototype, +//! time_bound: ::Prototype, +//! } +//! +//! #[contracttype] +//! pub struct TimeBound { +//! pub kind: TimeBoundKind, +//! pub timestamp: u64, +//! } +//! +//! #[contracttype] +//! pub enum TimeBoundKind { +//! Before, +//! After, +//! } +//! +//! fuzz_target!(|input: TestInput| { +//! let env = Env::default(); +//! let claim_address: Address = input.claim_address.into_val(&env); +//! let time_bound: TimeBound = input.time_bound.into_val(&env); +//! // fuzz the program based on the input +//! }); +//! ``` + +/// A reexport of the `arbitrary` crate. +/// +/// Used by the `contracttype` macro to derive `Arbitrary`. +pub use arbitrary; + +// Used often enough in fuzz tests to want direct access to it. +pub use arbitrary::Arbitrary; + +// Used by `contracttype` +#[doc(hidden)] +pub use std; + +pub use api::*; +pub use fuzz_test_helpers::*; + +/// The traits that must be implemented on Soroban types to support fuzzing. +/// +/// These allow for ergonomic conversion from a randomly-generated "prototype" +/// that implements `Arbitrary` into `Env`-"hosted" values that are paired with an +/// `Env`. +/// +/// These traits are intended to be easy to automatically derive. +mod api { + use crate::Env; + use crate::Val; + use crate::{IntoVal, TryFromVal}; + use arbitrary::Arbitrary; + + /// An `Env`-hosted contract value that can be randomly generated. + /// + /// Types that implement `SorabanArbitrary` have an associated "prototype" + /// type that implements [`Arbitrary`]. + /// + /// This exists partly so that the prototype can be named like + /// + /// ``` + /// # macro_rules! fuzz_target { + /// # (|$data:ident: $dty: ty| $body:block) => { }; + /// # } + /// # use soroban_sdk::{Address, Env, Vec, Bytes}; + /// # use soroban_sdk::testutils::arbitrary::SorobanArbitrary; + /// fuzz_target!(|input: ::Prototype| { + /// // ... + /// }); + /// ``` + // This also makes derivation of `SorobanArbitrary` for custom types easier + // since we depend on all fields also implementing `SorobanArbitrary`. + // + // The IntoVal + TryFromVal bounds are to satisfy + // the bounds of Vec and Map, so that collections of prototypes can be + // converted to contract types. + pub trait SorobanArbitrary: + TryFromVal + IntoVal + TryFromVal + { + /// A type that implements [`Arbitrary`] and can be converted to this + /// [`SorobanArbitrary`] type. + // NB: The `Arbitrary` bound here is not necessary for the correct use of + // `SorobanArbitrary`, but it makes the purpose clear. + type Prototype: for<'a> Arbitrary<'a>; + } +} + +/// Implementations of `soroban_sdk::testutils::arbitrary::api` for Rust scalar types. +/// +/// These types +/// +/// - do not have a distinct `Arbitrary` prototype, +/// i.e. they use themselves as the `SorobanArbitrary::Prototype` type, +/// - implement `Arbitrary` in the `arbitrary` crate, +/// - trivially implement `TryFromVal`, +/// +/// Examples: +/// +/// - `u32` +mod scalars { + use super::api::*; + + impl SorobanArbitrary for () { + type Prototype = (); + } + + impl SorobanArbitrary for bool { + type Prototype = bool; + } + + impl SorobanArbitrary for u32 { + type Prototype = u32; + } + + impl SorobanArbitrary for i32 { + type Prototype = i32; + } + + impl SorobanArbitrary for u64 { + type Prototype = u64; + } + + impl SorobanArbitrary for i64 { + type Prototype = i64; + } + + impl SorobanArbitrary for u128 { + type Prototype = u128; + } + + impl SorobanArbitrary for i128 { + type Prototype = i128; + } +} + +/// Implementations of `soroban_sdk::testutils::arbitrary::api` for Soroban types that do not +/// need access to the Soroban host environment. +/// +/// These types +/// +/// - do not have a distinct `Arbitrary` prototype, +/// i.e. they use themselves as the `SorobanArbitrary::Prototype` type, +/// - implement `Arbitrary` in the `soroban-env-common` crate, +/// - trivially implement `TryFromVal`, +/// +/// Examples: +/// +/// - `Error` +mod simple { + use super::api::*; + pub use crate::Error; + + impl SorobanArbitrary for Error { + type Prototype = Error; + } +} + +/// Implementations of `soroban_sdk::testutils::arbitrary::api` for Soroban types that do +/// need access to the Soroban host environment. +/// +/// These types +/// +/// - have a distinct `Arbitrary` prototype that derives `Arbitrary`, +/// - require an `Env` to be converted to their actual contract type. +/// +/// Examples: +/// +/// - `Vec` +mod objects { + use arbitrary::{Arbitrary, Result as ArbitraryResult, Unstructured}; + + use super::api::*; + use super::composite::ArbitraryVal; + use crate::env::FromVal; + use crate::ConversionError; + use crate::{Env, IntoVal, TryFromVal, TryIntoVal}; + + use crate::crypto::bn254::{ + Bn254Fp, Bn254Fr, Bn254G1Affine, Bn254G2Affine, BN254_FP_SERIALIZED_SIZE, + BN254_G1_SERIALIZED_SIZE, BN254_G2_SERIALIZED_SIZE, + }; + use crate::xdr::{Int256Parts, ScVal, UInt256Parts}; + use crate::{ + crypto::bls12_381::{ + Bls12381Fp, Bls12381Fp2, Bls12381Fr, Bls12381G1Affine, Bls12381G2Affine, + FP2_SERIALIZED_SIZE, FP_SERIALIZED_SIZE, G1_SERIALIZED_SIZE, G2_SERIALIZED_SIZE, + }, + Address, Bytes, BytesN, Duration, Map, MuxedAddress, String, Symbol, Timepoint, Val, Vec, + I256, U256, + }; + + use std::string::String as RustString; + use std::vec::Vec as RustVec; + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryOption(Option); + + impl SorobanArbitrary for Option + where + T: SorobanArbitrary, + Val: TryFromVal, + { + type Prototype = ArbitraryOption; + } + + impl TryFromVal> for Option + where + T: SorobanArbitrary, + { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryOption) -> Result { + match v.0 { + Some(ref t) => Ok(Some(t.into_val(env))), + None => Ok(None), + } + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryU256 { + parts: (u64, u64, u64, u64), + } + + impl SorobanArbitrary for U256 { + type Prototype = ArbitraryU256; + } + + impl TryFromVal for U256 { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryU256) -> Result { + let v = ScVal::U256(UInt256Parts { + hi_hi: v.parts.0, + hi_lo: v.parts.1, + lo_hi: v.parts.2, + lo_lo: v.parts.3, + }); + let v = Val::try_from_val(env, &v)?; + v.try_into_val(env) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryI256 { + parts: (i64, u64, u64, u64), + } + + impl SorobanArbitrary for I256 { + type Prototype = ArbitraryI256; + } + + impl TryFromVal for I256 { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryI256) -> Result { + let v = ScVal::I256(Int256Parts { + hi_hi: v.parts.0, + hi_lo: v.parts.1, + lo_hi: v.parts.2, + lo_lo: v.parts.3, + }); + let v = Val::try_from_val(env, &v)?; + v.try_into_val(env) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBytes { + vec: RustVec, + } + + impl SorobanArbitrary for Bytes { + type Prototype = ArbitraryBytes; + } + + impl TryFromVal for Bytes { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryBytes) -> Result { + Self::try_from_val(env, &v.vec.as_slice()) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryString { + inner: RustString, + } + + impl SorobanArbitrary for String { + type Prototype = ArbitraryString; + } + + impl TryFromVal for String { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryString) -> Result { + Self::try_from_val(env, &v.inner.as_str()) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBytesN { + array: [u8; N], + } + + impl SorobanArbitrary for BytesN { + type Prototype = ArbitraryBytesN; + } + + impl TryFromVal> for BytesN { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryBytesN) -> Result { + Self::try_from_val(env, &v.array) + } + } + + ////////////////////////////////// + + #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitrarySymbol { + s: RustString, + } + + impl<'a> Arbitrary<'a> for ArbitrarySymbol { + fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult { + let valid_chars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + let valid_chars = valid_chars.as_bytes(); + let mut chars = vec![]; + let len = u.int_in_range(0..=32)?; + for _ in 0..len { + let ch = u.choose(valid_chars)?; + chars.push(*ch); + } + Ok(ArbitrarySymbol { + s: RustString::from_utf8(chars).expect("utf8"), + }) + } + } + + impl SorobanArbitrary for Symbol { + type Prototype = ArbitrarySymbol; + } + + impl TryFromVal for Symbol { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitrarySymbol) -> Result { + Self::try_from_val(env, &v.s.as_str()) + } + } + + ////////////////////////////////// + + #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryVec { + Good(RustVec), + // Vec can be constructed with non-T values. + Wrong(RustVec), + } + + impl<'a, T> Arbitrary<'a> for ArbitraryVec + where + T: Arbitrary<'a>, + { + fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult> { + // How frequently we provide ArbitraryVec::Wrong + const WRONG_TYPE_RATIO: (u16, u16) = (1, 1000); + + if u.ratio(WRONG_TYPE_RATIO.0, WRONG_TYPE_RATIO.1)? { + Ok(ArbitraryVec::Wrong(Arbitrary::arbitrary(u)?)) + } else { + Ok(ArbitraryVec::Good(Arbitrary::arbitrary(u)?)) + } + } + } + + impl SorobanArbitrary for Vec + where + T: SorobanArbitrary, + { + type Prototype = ArbitraryVec; + } + + impl TryFromVal> for Vec + where + T: SorobanArbitrary, + { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryVec) -> Result { + match v { + ArbitraryVec::Good(vec) => { + let mut buf: Vec = Vec::new(env); + for item in vec.iter() { + buf.push_back(item.into_val(env)); + } + Ok(buf) + } + ArbitraryVec::Wrong(vec) => { + let mut buf: Vec = Vec::new(env); + for item in vec.iter() { + buf.push_back(item.into_val(env)); + } + Ok(Vec::::from_val(env, &buf.to_val())) + } + } + } + } + + ////////////////////////////////// + + #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryMap { + Good(RustVec<(K, V)>), + // Maps can be constructed with non-T K/Vs + WrongKey(RustVec<(ArbitraryVal, V)>), + WrongValue(RustVec<(K, ArbitraryVal)>), + } + + impl<'a, K, V> Arbitrary<'a> for ArbitraryMap + where + K: Arbitrary<'a>, + V: Arbitrary<'a>, + { + fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult> { + // How frequently we provide ArbitraryMap::Wrong* + const WRONG_TYPE_RATIO: (u16, u16) = (1, 1000); + + if u.ratio(WRONG_TYPE_RATIO.0, WRONG_TYPE_RATIO.1)? { + if u.arbitrary::()? { + Ok(ArbitraryMap::WrongKey(Arbitrary::arbitrary(u)?)) + } else { + Ok(ArbitraryMap::WrongValue(Arbitrary::arbitrary(u)?)) + } + } else { + Ok(ArbitraryMap::Good(Arbitrary::arbitrary(u)?)) + } + } + } + + impl SorobanArbitrary for Map + where + K: SorobanArbitrary, + V: SorobanArbitrary, + { + type Prototype = ArbitraryMap; + } + + impl TryFromVal> for Map + where + K: SorobanArbitrary, + V: SorobanArbitrary, + { + type Error = ConversionError; + fn try_from_val( + env: &Env, + v: &ArbitraryMap, + ) -> Result { + match v { + ArbitraryMap::Good(vec) => { + let mut map: Map = Map::new(env); + for (k, v) in vec.iter() { + map.set(k.into_val(env), v.into_val(env)); + } + Ok(map) + } + ArbitraryMap::WrongKey(vec) => { + let mut map: Map = Map::new(env); + for (k, v) in vec.iter() { + map.set(k.into_val(env), v.into_val(env)); + } + Ok(Map::::from_val(env, &map.to_val())) + } + ArbitraryMap::WrongValue(vec) => { + let mut map: Map = Map::new(env); + for (k, v) in vec.iter() { + map.set(k.into_val(env), v.into_val(env)); + } + Ok(Map::::from_val(env, &map.to_val())) + } + } + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryAddress { + inner: [u8; 32], + } + + impl SorobanArbitrary for Address { + type Prototype = ArbitraryAddress; + } + + impl TryFromVal for Address { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryAddress) -> Result { + use crate::env::xdr::{ContractId, Hash, ScAddress}; + + let sc_addr = ScVal::Address(ScAddress::Contract(ContractId(Hash(v.inner)))); + Ok(sc_addr.into_val(env)) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryMuxedAddress { + Address(ArbitraryAddress), + Muxed { ed25519: [u8; 32], id: u64 }, + } + + impl SorobanArbitrary for MuxedAddress { + type Prototype = ArbitraryMuxedAddress; + } + + impl TryFromVal for MuxedAddress { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryMuxedAddress) -> Result { + use crate::env::xdr::{MuxedEd25519Account, ScAddress, Uint256}; + + let sc_addr = match v { + ArbitraryMuxedAddress::Address(v) => { + let address = Address::try_from_val(env, v)?; + return Ok(address.into()); + } + ArbitraryMuxedAddress::Muxed { ed25519, id } => { + ScVal::Address(ScAddress::MuxedAccount(MuxedEd25519Account { + ed25519: Uint256(*ed25519), + id: *id, + })) + } + }; + Ok(sc_addr.into_val(env)) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryTimepoint { + inner: u64, + } + + impl SorobanArbitrary for Timepoint { + type Prototype = ArbitraryTimepoint; + } + + impl TryFromVal for Timepoint { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryTimepoint) -> Result { + let sc_timepoint = ScVal::Timepoint(crate::xdr::TimePoint::from(v.inner)); + Ok(sc_timepoint.into_val(env)) + } + } + + ////////////////////////////////// + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryDuration { + inner: u64, + } + + impl SorobanArbitrary for Duration { + type Prototype = ArbitraryDuration; + } + + impl TryFromVal for Duration { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryDuration) -> Result { + let sc_duration = ScVal::Duration(crate::xdr::Duration::from(v.inner)); + Ok(sc_duration.into_val(env)) + } + } + + // For Bls12381Fp (48 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBls12381Fp { + bytes: [u8; FP_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bls12381Fp { + type Prototype = ArbitraryBls12381Fp; + } + + impl TryFromVal for Bls12381Fp { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBls12381Fp) -> Result { + let mut bytes = v.bytes; + // Ensure the value is strictly less than the BLS12-381 base field modulus + // p = 0x1a0111ea... by restricting the most significant byte. + bytes[0] %= 0x1a; + Ok(Bls12381Fp::from_array(env, &bytes)) + } + } + + // For Bls12381Fp2 (96 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBls12381Fp2 { + bytes: [u8; FP2_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bls12381Fp2 { + type Prototype = ArbitraryBls12381Fp2; + } + + impl TryFromVal for Bls12381Fp2 { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBls12381Fp2) -> Result { + let mut bytes = v.bytes; + // Ensure both Fp components are strictly less than the modulus + bytes[0] %= 0x1a; + bytes[FP_SERIALIZED_SIZE] %= 0x1a; + Ok(Bls12381Fp2::from_array(env, &bytes)) + } + } + + // For Bls12381G1Affine (96 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBls12381G1Affine { + bytes: [u8; G1_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bls12381G1Affine { + type Prototype = ArbitraryBls12381G1Affine; + } + + impl TryFromVal for Bls12381G1Affine { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBls12381G1Affine) -> Result { + let mut bytes = v.bytes; + // the top 3 bits in a G1 point are reserved for flags: + // compression_flag (bit 0), infinity_flag (bit 1) and sort_flag + // (bit 2). Only infinity_flag is possible to be set, in which case + // the rest of the bytes must be zeros. The host will reject any + // invalid input. Manually taking care of the flag bits here to give + // it better chance of being a valid input. + const INFINITY_FLAG: u8 = 0b0100_0000; + const FLAG_MASK: u8 = 0b1110_0000; + if (bytes[0] & INFINITY_FLAG) != 0 { + // infinity flag set, clear rest of bits + bytes = [0; 96]; + bytes[0] = INFINITY_FLAG; + } else { + // not an infinity point, we clear the flag bits + bytes[0] &= !FLAG_MASK + } + Ok(Bls12381G1Affine::from_array(env, &bytes)) + } + } + + // For Bls12381G2Affine (192 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBls12381G2Affine { + bytes: [u8; G2_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bls12381G2Affine { + type Prototype = ArbitraryBls12381G2Affine; + } + + impl TryFromVal for Bls12381G2Affine { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBls12381G2Affine) -> Result { + let mut bytes = v.bytes; + // the top 3 bits in a G1 point are reserved for flags: + // compression_flag (bit 0), infinity_flag (bit 1) and sort_flag + // (bit 2). Only infinity_flag is possible to be set, in which case + // the rest of the bytes must be zeros. The host will reject any + // invalid input. Manually taking care of the flag bits here to give + // it better chance of being a valid input. + const INFINITY_FLAG: u8 = 0b0100_0000; + const FLAG_MASK: u8 = 0b1110_0000; + if (bytes[0] & INFINITY_FLAG) != 0 { + // infinity flag set, clear rest of bits + bytes = [0; 192]; + bytes[0] = INFINITY_FLAG; + } else { + // not an infinity point, we clear the flag bits + bytes[0] &= !FLAG_MASK + } + Ok(Bls12381G2Affine::from_array(env, &bytes)) + } + } + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBls12381Fr { + bytes: [u8; 32], + } + + impl SorobanArbitrary for Bls12381Fr { + type Prototype = ArbitraryBls12381Fr; + } + + impl TryFromVal for Bls12381Fr { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBls12381Fr) -> Result { + // Convert bytes to Bls12381Fr via U256 + Ok(Bls12381Fr::from_bytes(BytesN::from_array(env, &v.bytes))) + } + } + + // BN254 types + + // For BN254 G1Affine (64 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBn254G1Affine { + bytes: [u8; BN254_G1_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bn254G1Affine { + type Prototype = ArbitraryBn254G1Affine; + } + + impl TryFromVal for Bn254G1Affine { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBn254G1Affine) -> Result { + Ok(Bn254G1Affine::from_array(env, &v.bytes)) + } + } + + // For BN254 G2Affine (128 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBn254G2Affine { + bytes: [u8; BN254_G2_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bn254G2Affine { + type Prototype = ArbitraryBn254G2Affine; + } + + impl TryFromVal for Bn254G2Affine { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBn254G2Affine) -> Result { + Ok(Bn254G2Affine::from_array(env, &v.bytes)) + } + } + + // For Bn254Fp (32 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBn254Fp { + bytes: [u8; BN254_FP_SERIALIZED_SIZE], + } + + impl SorobanArbitrary for Bn254Fp { + type Prototype = ArbitraryBn254Fp; + } + + impl TryFromVal for Bn254Fp { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBn254Fp) -> Result { + let mut bytes = v.bytes; + // Ensure the value is strictly less than the BN254 base field modulus + // p = 0x30644e72... by restricting the most significant byte. + bytes[0] %= 0x30; + Ok(Bn254Fp::from_array(env, &bytes)) + } + } + + // For BN254 Fr (32 bytes) + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct ArbitraryBn254Fr { + bytes: [u8; 32], + } + + impl SorobanArbitrary for Bn254Fr { + type Prototype = ArbitraryBn254Fr; + } + + impl TryFromVal for Bn254Fr { + type Error = ConversionError; + + fn try_from_val(env: &Env, v: &ArbitraryBn254Fr) -> Result { + Ok(Bn254Fr::from_bytes(BytesN::from_array(env, &v.bytes))) + } + } +} + +/// Implementations of `soroban_sdk::testutils::arbitrary::api` for tuples of Soroban types. +/// +/// The implementation is similar to objects, but macroized. +mod tuples { + use super::api::*; + use crate::ConversionError; + use crate::{Env, IntoVal, TryFromVal, TryIntoVal, Val}; + use arbitrary::Arbitrary; + + macro_rules! impl_tuple { + ($name: ident, $($ty: ident),+ ) => { + #[allow(non_snake_case)] // naming fields T1, etc. + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub struct $name<$($ty,)*> { + $($ty: $ty,)* + } + + impl<$($ty,)*> SorobanArbitrary for ($($ty,)*) + where $($ty: SorobanArbitrary + TryIntoVal,)* + { + type Prototype = $name<$($ty::Prototype,)*>; + } + + impl<$($ty,)*> TryFromVal> for ($($ty,)*) + where $($ty: SorobanArbitrary,)* + { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &$name<$($ty::Prototype,)*>) -> Result { + Ok(($( + v.$ty.into_val(env), + )*)) + } + } + } + } + + impl_tuple!(ArbitraryTuple1, T1); + impl_tuple!(ArbitraryTuple2, T1, T2); + impl_tuple!(ArbitraryTuple3, T1, T2, T3); + impl_tuple!(ArbitraryTuple4, T1, T2, T3, T4); + impl_tuple!(ArbitraryTuple5, T1, T2, T3, T4, T5); + impl_tuple!(ArbitraryTuple6, T1, T2, T3, T4, T5, T6); + impl_tuple!(ArbitraryTuple7, T1, T2, T3, T4, T5, T6, T7); + impl_tuple!(ArbitraryTuple8, T1, T2, T3, T4, T5, T6, T7, T8); + impl_tuple!(ArbitraryTuple9, T1, T2, T3, T4, T5, T6, T7, T8, T9); + impl_tuple!(ArbitraryTuple10, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); + impl_tuple!( + ArbitraryTuple11, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11 + ); + impl_tuple!( + ArbitraryTuple12, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12 + ); +} + +/// Implementations of `soroban_sdk::testutils::arbitrary::api` for `Val`. +mod composite { + use arbitrary::Arbitrary; + + use super::api::*; + use crate::ConversionError; + use crate::{Env, IntoVal, TryFromVal}; + + use super::objects::*; + use super::simple::*; + use crate::{ + Address, Bytes, BytesN, Duration, Map, String, Symbol, Timepoint, Val, Vec, I256, U256, + }; + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryVal { + Void, + Bool(bool), + Error(Error), + U32(u32), + I32(i32), + U64(u64), + I64(i64), + U128(u128), + I128(i128), + U256(ArbitraryU256), + I256(ArbitraryI256), + Bytes(ArbitraryBytes), + String(ArbitraryString), + Symbol(ArbitrarySymbol), + Vec(ArbitraryValVec), + Map(ArbitraryValMap), + Address(ArbitraryAddress), + Timepoint(ArbitraryTimepoint), + Duration(ArbitraryDuration), + Option(ArbitraryValOption), + } + + impl SorobanArbitrary for Val { + type Prototype = ArbitraryVal; + } + + impl TryFromVal for Val { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryVal) -> Result { + Ok(match v { + ArbitraryVal::Void => Val::VOID.into(), + ArbitraryVal::Bool(v) => v.into_val(env), + ArbitraryVal::Error(v) => v.into_val(env), + ArbitraryVal::U32(v) => v.into_val(env), + ArbitraryVal::I32(v) => v.into_val(env), + ArbitraryVal::U64(v) => v.into_val(env), + ArbitraryVal::I64(v) => v.into_val(env), + ArbitraryVal::U256(v) => { + let v: U256 = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::I256(v) => { + let v: I256 = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::U128(v) => v.into_val(env), + ArbitraryVal::I128(v) => v.into_val(env), + ArbitraryVal::Bytes(v) => { + let v: Bytes = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::String(v) => { + let v: String = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::Symbol(v) => { + let v: Symbol = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::Vec(v) => v.into_val(env), + ArbitraryVal::Map(v) => v.into_val(env), + ArbitraryVal::Address(v) => { + let v: Address = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::Timepoint(v) => { + let v: Timepoint = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::Duration(v) => { + let v: Duration = v.into_val(env); + v.into_val(env) + } + ArbitraryVal::Option(v) => v.into_val(env), + }) + } + } + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryValVec { + Void( as SorobanArbitrary>::Prototype), + Bool( as SorobanArbitrary>::Prototype), + Error( as SorobanArbitrary>::Prototype), + U32( as SorobanArbitrary>::Prototype), + I32( as SorobanArbitrary>::Prototype), + U64( as SorobanArbitrary>::Prototype), + I64( as SorobanArbitrary>::Prototype), + U128( as SorobanArbitrary>::Prototype), + I128( as SorobanArbitrary>::Prototype), + U256( as SorobanArbitrary>::Prototype), + I256( as SorobanArbitrary>::Prototype), + Bytes( as SorobanArbitrary>::Prototype), + BytesN(> as SorobanArbitrary>::Prototype), + String( as SorobanArbitrary>::Prototype), + Symbol( as SorobanArbitrary>::Prototype), + Vec(> as SorobanArbitrary>::Prototype), + Map(> as SorobanArbitrary>::Prototype), + Address( as SorobanArbitrary>::Prototype), + Timepoint( as SorobanArbitrary>::Prototype), + Duration( as SorobanArbitrary>::Prototype), + Val( as SorobanArbitrary>::Prototype), + } + + impl TryFromVal for Val { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryValVec) -> Result { + Ok(match v { + ArbitraryValVec::Void(v) => { + let v: Vec<()> = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Bool(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Error(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::U32(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::I32(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::U64(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::I64(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::U128(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::I128(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::U256(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::I256(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Bytes(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::BytesN(v) => { + let v: Vec> = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::String(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Symbol(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Vec(v) => { + let v: Vec> = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Map(v) => { + let v: Vec> = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Address(v) => { + let v: Vec
= v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Timepoint(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Duration(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + ArbitraryValVec::Val(v) => { + let v: Vec = v.into_val(env); + v.into_val(env) + } + }) + } + } + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryValMap { + VoidToVoid( as SorobanArbitrary>::Prototype), + BoolToBool( as SorobanArbitrary>::Prototype), + ErrorToError( as SorobanArbitrary>::Prototype), + U32ToU32( as SorobanArbitrary>::Prototype), + I32ToI32( as SorobanArbitrary>::Prototype), + U64ToU64( as SorobanArbitrary>::Prototype), + I64ToI64( as SorobanArbitrary>::Prototype), + U128ToU128( as SorobanArbitrary>::Prototype), + I128ToI128( as SorobanArbitrary>::Prototype), + U256ToU256( as SorobanArbitrary>::Prototype), + I256ToI256( as SorobanArbitrary>::Prototype), + BytesToBytes( as SorobanArbitrary>::Prototype), + BytesNToBytesN(, BytesN<32>> as SorobanArbitrary>::Prototype), + StringToString( as SorobanArbitrary>::Prototype), + SymbolToSymbol( as SorobanArbitrary>::Prototype), + VecToVec(, Vec> as SorobanArbitrary>::Prototype), + MapToMap(, Map> as SorobanArbitrary>::Prototype), + AddressToAddress( as SorobanArbitrary>::Prototype), + TimepointToTimepoint( as SorobanArbitrary>::Prototype), + DurationToDuration( as SorobanArbitrary>::Prototype), + ValToVal( as SorobanArbitrary>::Prototype), + OptionToOption(, Option> as SorobanArbitrary>::Prototype), + } + + impl TryFromVal for Val { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryValMap) -> Result { + Ok(match v { + ArbitraryValMap::VoidToVoid(v) => { + let v: Map<(), ()> = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::BoolToBool(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::ErrorToError(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::U32ToU32(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::I32ToI32(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::U64ToU64(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::I64ToI64(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::U128ToU128(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::I128ToI128(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::U256ToU256(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::I256ToI256(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::BytesToBytes(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::BytesNToBytesN(v) => { + let v: Map, BytesN<32>> = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::StringToString(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::SymbolToSymbol(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::VecToVec(v) => { + let v: Map, Vec> = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::MapToMap(v) => { + let v: Map, Map> = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::AddressToAddress(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::TimepointToTimepoint(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::DurationToDuration(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::ValToVal(v) => { + let v: Map = v.into_val(env); + v.into_val(env) + } + ArbitraryValMap::OptionToOption(v) => { + let v: Map, Option> = v.into_val(env); + v.into_val(env) + } + }) + } + } + + #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] + pub enum ArbitraryValOption { + Void( as SorobanArbitrary>::Prototype), + Bool( as SorobanArbitrary>::Prototype), + Error( as SorobanArbitrary>::Prototype), + U32( as SorobanArbitrary>::Prototype), + I32( as SorobanArbitrary>::Prototype), + U64( as SorobanArbitrary>::Prototype), + I64( as SorobanArbitrary>::Prototype), + U128( as SorobanArbitrary>::Prototype), + I128( as SorobanArbitrary>::Prototype), + U256( as SorobanArbitrary>::Prototype), + I256( as SorobanArbitrary>::Prototype), + Bytes( as SorobanArbitrary>::Prototype), + BytesN(> as SorobanArbitrary>::Prototype), + String( as SorobanArbitrary>::Prototype), + Symbol( as SorobanArbitrary>::Prototype), + Vec(> as SorobanArbitrary>::Prototype), + Map(> as SorobanArbitrary>::Prototype), + Address( as SorobanArbitrary>::Prototype), + Timepoint( as SorobanArbitrary>::Prototype), + Duration( as SorobanArbitrary>::Prototype), + Val(Box< as SorobanArbitrary>::Prototype>), + } + + impl TryFromVal for Val { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &ArbitraryValOption) -> Result { + Ok(match v { + ArbitraryValOption::Void(v) => { + let v: Option<()> = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Bool(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Error(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::U32(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::I32(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::U64(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::I64(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::U128(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::I128(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::U256(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::I256(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Bytes(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::BytesN(v) => { + let v: Option> = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::String(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Symbol(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Vec(v) => { + let v: Option> = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Map(v) => { + let v: Option> = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Address(v) => { + let v: Option
= v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Timepoint(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Duration(v) => { + let v: Option = v.into_val(env); + v.into_val(env) + } + ArbitraryValOption::Val(v) => { + let v: Option = (**v).into_val(env); + v.into_val(env) + } + }) + } + } +} + +/// Additional tools for writing fuzz tests. +mod fuzz_test_helpers { + use soroban_env_host::testutils::call_with_suppressed_panic_hook; + + /// Catch panics within a fuzz test. + /// + /// The `cargo-fuzz` test harness turns panics into test failures, + /// immediately aborting the process. + /// + /// This function catches panics while temporarily disabling the + /// `cargo-fuzz` panic handler. + /// + /// # Example + /// + /// ``` + /// # macro_rules! fuzz_target { + /// # (|$data:ident: $dty: ty| $body:block) => { }; + /// # } + /// # struct ExampleContract; + /// # impl ExampleContract { + /// # fn new(e: &soroban_sdk::Env, b: &soroban_sdk::BytesN<32>) { } + /// # fn deposit(&self, a: soroban_sdk::Address, n: i128) { } + /// # } + /// use soroban_sdk::{Address, Env}; + /// use soroban_sdk::testutils::arbitrary::{Arbitrary, SorobanArbitrary}; + /// + /// #[derive(Arbitrary, Debug)] + /// struct FuzzDeposit { + /// deposit_amount: i128, + /// deposit_address:
::Prototype, + /// } + /// + /// fuzz_target!(|input: FuzzDeposit| { + /// let env = Env::default(); + /// + /// let contract = ExampleContract::new(env, &env.register_contract(None, ExampleContract {})); + /// + /// let addresses: Address = input.deposit_address.into_val(&env); + /// let r = contract.try_deposit(deposit_address, input.deposit_amount); + /// }); + /// ``` + #[deprecated(note = "use [Env::try_invoke] or the try_ functions on a contract client")] + pub fn fuzz_catch_panic(f: F) -> std::thread::Result + where + F: FnOnce() -> R, + { + call_with_suppressed_panic_hook(std::panic::AssertUnwindSafe(f)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + Address, Bytes, BytesN, Duration, Error, Map, String, Symbol, Timepoint, Val, Vec, I256, + U256, + }; + use crate::{Env, IntoVal}; + use arbitrary::{Arbitrary, Unstructured}; + use rand::{RngCore, SeedableRng}; + + fn run_test() + where + T: SorobanArbitrary, + T::Prototype: for<'a> Arbitrary<'a>, + { + let env = Env::default(); + let mut rng = rand::rngs::StdRng::seed_from_u64(0); + let mut rng_data = [0u8; 64]; + + for _ in 0..100 { + rng.fill_bytes(&mut rng_data); + let mut unstructured = Unstructured::new(&rng_data); + loop { + match T::Prototype::arbitrary(&mut unstructured) { + Ok(input) => { + let _val: T = input.into_val(&env); + break; + } + Err(_) => {} + } + } + } + } + + #[test] + fn test_unit() { + run_test::<()>() + } + + #[test] + fn test_bool() { + run_test::() + } + + #[test] + fn test_u32() { + run_test::() + } + + #[test] + fn test_i32() { + run_test::() + } + + #[test] + fn test_u64() { + run_test::() + } + + #[test] + fn test_i64() { + run_test::() + } + + #[test] + fn test_u128() { + run_test::() + } + + #[test] + fn test_i128() { + run_test::() + } + + #[test] + fn test_u256() { + run_test::() + } + + #[test] + fn test_i256() { + run_test::() + } + + #[test] + fn test_bytes() { + run_test::() + } + + #[test] + fn test_string() { + run_test::() + } + + #[test] + fn test_bytes_n() { + run_test::>() + } + + #[test] + fn test_symbol() { + run_test::() + } + + #[test] + fn test_address() { + run_test::
() + } + + #[test] + fn test_val() { + run_test::() + } + + #[test] + fn test_vec_void() { + run_test::>() + } + + #[test] + fn test_vec_bool() { + run_test::>() + } + + #[test] + fn test_vec_error() { + run_test::>() + } + + #[test] + fn test_vec_u32() { + run_test::>() + } + + #[test] + fn test_vec_i32() { + run_test::>() + } + + #[test] + fn test_vec_u64() { + run_test::>() + } + + #[test] + fn test_vec_i64() { + run_test::>() + } + + #[test] + fn test_vec_u128() { + run_test::>() + } + + #[test] + fn test_vec_i128() { + run_test::>() + } + + #[test] + fn test_vec_u256() { + run_test::>() + } + + #[test] + fn test_vec_i256() { + run_test::>() + } + + #[test] + fn test_vec_bytes() { + run_test::>() + } + + #[test] + fn test_vec_bytes_n() { + run_test::>>() + } + + #[test] + fn test_vec_string() { + run_test::>() + } + + #[test] + fn test_vec_symbol() { + run_test::>() + } + + #[test] + fn test_vec_vec_u32() { + run_test::>>() + } + + #[test] + fn test_vec_vec_bytes() { + run_test::>>() + } + + #[test] + fn test_vec_timepoint() { + run_test::>() + } + + #[test] + fn test_vec_duration() { + run_test::>() + } + + #[test] + fn test_vec_map_u32() { + run_test::>>() + } + + #[test] + fn test_vec_address() { + run_test::>() + } + + #[test] + fn test_vec_val() { + run_test::>() + } + + #[test] + fn test_map_void() { + run_test::>() + } + + #[test] + fn test_map_bool() { + run_test::>() + } + + #[test] + fn test_map_error() { + run_test::>() + } + + #[test] + fn test_map_u32() { + run_test::>>() + } + + #[test] + fn test_map_i32() { + run_test::>>() + } + + #[test] + fn test_map_u64() { + run_test::>>() + } + + #[test] + fn test_map_i64() { + run_test::>>() + } + + #[test] + fn test_map_u128() { + run_test::>>() + } + + #[test] + fn test_map_i128() { + run_test::>>() + } + + #[test] + fn test_map_u256() { + run_test::>>() + } + + #[test] + fn test_map_i256() { + run_test::>>() + } + + #[test] + fn test_map_bytes() { + run_test::>() + } + + #[test] + fn test_map_bytes_n() { + run_test::, Bytes>>() + } + + #[test] + fn test_map_string() { + run_test::>() + } + + #[test] + fn test_map_symbol() { + run_test::>() + } + + #[test] + fn test_map_vec_u32() { + run_test::, Vec>>() + } + + #[test] + fn test_map_vec_bytes() { + run_test::, Vec>>() + } + + #[test] + fn test_map_timepoint() { + run_test::>() + } + + #[test] + fn test_map_duration() { + run_test::>() + } + + fn test_map_map_u32() { + run_test::, Map>>() + } + + #[test] + fn test_map_address() { + run_test::>() + } + + #[test] + fn test_map_val() { + run_test::>() + } + + #[test] + fn test_timepoint() { + run_test::() + } + + #[test] + fn test_duration() { + run_test::() + } + + #[test] + fn test_tuples() { + run_test::<(u32,)>(); + run_test::<(u32, u32)>(); + run_test::<(u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); + run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); + + run_test::<(u32, Address, Vec, Map)>(); + } + + #[test] + fn test_option() { + run_test::>(); + run_test::>>(); + } + + // Test that sometimes generated vecs have the wrong element types. + #[test] + fn test_vec_wrong_types() { + // These number are tuned for StdRng. + // If StdRng ever changes the test could break. + let iterations = 1000; + let seed = 3; + let acceptable_ratio = 900; + + let (mut seen_good, mut seen_bad, mut seen_empty) = (0, 0, 0); + + let env = Env::default(); + let mut rng = rand::rngs::StdRng::seed_from_u64(seed); + let mut rng_data = [0u8; 64]; + + for _ in 0..iterations { + rng.fill_bytes(&mut rng_data); + let mut unstructured = Unstructured::new(&rng_data); + let input = as SorobanArbitrary>::Prototype::arbitrary(&mut unstructured) + .expect("SorobanArbitrary"); + let vec: Vec = input.into_val(&env); + + let has_good_elts = (0..vec.len()).all(|i| vec.try_get(i).is_ok()) && !vec.is_empty(); + // Look for elements that cause an error. + let has_bad_elt = (0..vec.len()).any(|i| vec.try_get(i).is_err()); + + if has_bad_elt { + seen_bad += 1; + } else if has_good_elts { + seen_good += 1; + } else { + seen_empty += 1; + } + } + + assert!(seen_good > 0); + assert!(seen_bad > 0); + + // sanity check the ratio of good to bad + assert!(seen_good * seen_empty > seen_bad * acceptable_ratio); + } + + // Test that sometimes generated maps have the wrong element types. + #[test] + fn test_map_wrong_types() { + // These number are tuned for StdRng. + // If StdRng ever changes the test could break. + let iterations = 4000; + let seed = 13; + let acceptable_ratio = 900; + + let (mut seen_good, mut seen_bad_key, mut seen_bad_value, mut seen_empty) = (0, 0, 0, 0); + + let env = Env::default(); + let mut rng = rand::rngs::StdRng::seed_from_u64(seed); + let mut rng_data = [0u8; 128]; + + for _ in 0..iterations { + rng.fill_bytes(&mut rng_data); + let mut unstructured = Unstructured::new(&rng_data); + let input = + as SorobanArbitrary>::Prototype::arbitrary(&mut unstructured) + .expect("SorobanArbitrary"); + let map: Map = input.into_val(&env); + + // Look for elements that cause an error. + let keys = map.keys(); + let values = map.values(); + + let has_good_keys = + (0..keys.len()).all(|i| keys.try_get(i).is_ok()) && !keys.is_empty(); + let has_good_values = + (0..values.len()).all(|i| values.try_get(i).is_ok()) && !keys.is_empty(); + let has_bad_key = (0..keys.len()).any(|i| keys.try_get(i).is_err()); + let has_bad_value = (0..values.len()).any(|i| values.try_get(i).is_err()); + + if has_bad_key { + seen_bad_key += 1; + } else if has_bad_value { + seen_bad_value += 1; + } else if has_good_keys && has_good_values { + seen_good += 1; + } else { + seen_empty += 1; + } + } + + assert!(seen_good > 0); + assert!(seen_bad_key > 0); + assert!(seen_bad_value > 0); + + // sanity check the ratio of good to bad + assert!(seen_good * seen_empty > (seen_bad_key + seen_bad_value) * acceptable_ratio); + } + + mod user_defined_types { + use super::run_test; + use crate as soroban_sdk; + use crate::{ + Address, Bytes, BytesN, Duration, Error, Map, Symbol, Timepoint, Vec, I256, U256, + }; + use soroban_sdk::contracttype; + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + struct PrivStruct { + count_u: u32, + count_i: i32, + bytes_n: BytesN<32>, + vec: Vec, + map: Map>, + u256: U256, + i156: I256, + error: Error, + address: Address, + symbol: Symbol, + duration: Duration, + timepoint: Timepoint, + nil: (), + vec_tuple: Vec<(u32, Address)>, + option: Option, + } + + #[test] + fn test_user_defined_priv_struct() { + run_test::(); + } + + #[test] + fn test_option_user_defined_priv_struct() { + run_test::>(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + struct PrivStructPubFields { + pub count_u: u32, + pub count_i: i32, + pub bytes_n: BytesN<32>, + pub vec: Vec, + pub map: Map>, + } + + #[test] + fn test_user_defined_priv_struct_pub_fields() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct PubStruct { + count_u: u32, + count_i: i32, + bytes_n: BytesN<32>, + vec: Vec, + map: Map>, + } + + #[test] + fn test_user_defined_pub_struct() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct PubStructPubFields { + pub count_u: u32, + pub count_i: i32, + pub bytes_n: BytesN<32>, + pub vec: Vec, + pub map: Map>, + } + + #[test] + fn test_user_defined_pubstruct_pub_fields() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + struct PrivTupleStruct( + u32, + i32, + BytesN<32>, + Vec, + Map>, + Vec<(u32, Address)>, + Option, + ); + + #[test] + fn test_user_defined_priv_tuple_struct() { + run_test::(); + } + + #[test] + fn test_option_user_defined_priv_tuple_struct() { + run_test::>(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + struct PrivTupleStructPubFields( + pub u32, + pub i32, + pub BytesN<32>, + pub Vec, + pub Map>, + pub Vec<(u32, Address)>, + ); + + #[test] + fn test_user_defined_priv_tuple_struct_pub_fields() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct PubTupleStruct(u32, i32, BytesN<32>, Vec, Map>); + + #[test] + fn test_user_defined_pub_tuple_struct() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct PubTupleStructPubFields( + pub u32, + pub i32, + pub BytesN<32>, + pub Vec, + pub Map>, + pub Vec<(u32, Address)>, + ); + + #[test] + fn test_user_defined_pub_tuple_struct_pub_fields() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub(crate) struct PubCrateStruct(u32); + + #[test] + fn test_user_defined_pub_crate_struct() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + enum PrivEnum { + A(u32), + Aa(u32, u32), + C, + D, + E(Vec<(u32, Address)>), + F(Option), + } + + #[test] + fn test_user_defined_priv_enum() { + run_test::(); + } + + #[test] + fn test_option_user_defined_priv_enum() { + run_test::>(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub enum PubEnum { + A(u32), + C, + D, + } + + #[test] + fn test_user_defined_pub_enum() { + run_test::(); + } + + #[contracttype] + #[derive(Clone, Debug, Eq, PartialEq)] + pub(crate) enum PubCrateEnum { + A(u32), + C, + D, + } + + #[test] + fn test_user_defined_pub_crate_enum() { + run_test::(); + } + + #[contracttype] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + enum PrivEnumInt { + A = 1, + C = 2, + D = 3, + } + + #[test] + fn test_user_defined_priv_enum_int() { + run_test::(); + } + + #[contracttype] + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum PubEnumInt { + A = 1, + C = 2, + D = 3, + } + + #[test] + fn test_user_defined_pub_enum_int() { + run_test::(); + } + + #[test] + fn test_declared_inside_a_fn() { + #[contracttype] + struct Foo { + a: u32, + } + + #[contracttype] + enum Bar { + Baz, + Qux, + } + + run_test::(); + run_test::(); + } + + fn test_structs_and_enums_inside_tuples() { + #[contracttype] + struct Foo(u32); + + #[contracttype] + enum Bar { + Baz, + } + + run_test::<(Foo, Bar)>(); + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs new file mode 100644 index 0000000..a1e9e54 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs @@ -0,0 +1,153 @@ +use soroban_env_host::{ + fees::FeeConfiguration, FeeEstimate, InvocationResourceLimits, InvocationResources, +}; + +use crate::{testutils::budget::Budget, Env}; + +pub struct CostEstimate { + env: Env, +} + +impl CostEstimate { + pub(crate) fn new(env: Env) -> Self { + Self { env } + } + + /// Returns the resources metered during the last top level contract + /// invocation. + /// Take the return value with a grain of salt. The returned resources mostly + /// correspond only to the operations that have happened during the host + /// invocation, i.e. this won't try to simulate the work that happens in + /// production scenarios (e.g. certain XDR rountrips). This also doesn't try + /// to model resources related to the transaction size. + /// + /// The returned value is as useful as the preceding setup, e.g. if a test + /// contract is used instead of a Wasm contract, all the costs related to + /// VM instantiation and execution, as well as Wasm reads/rent bumps will be + /// missed. + pub fn resources(&self) -> InvocationResources { + if let Some(res) = self.env.host().get_last_invocation_resources() { + res + } else { + panic!("Invocation cost estimate is not available. Make sure invocation cost metering is enabled in the EnvTestConfig and this is called after an invocation.") + } + } + + /// Estimates the fee for the last invocation's resources, i.e. the + /// resources returned by `resources()`. + /// + /// The fees are computed using the snapshot of the Stellar Pubnet fees made + /// on 2024-12-11. + /// + /// Take the return value with a grain of salt as both the resource estimate + /// and the fee rates may be imprecise. + /// + /// The returned value is as useful as the preceding setup, e.g. if a test + /// contract is used instead of a Wasm contract, all the costs related to + /// VM instantiation and execution, as well as Wasm reads/rent bumps will be + /// missed. + pub fn fee(&self) -> FeeEstimate { + // This is a snapshot of the fees as of 2024-12-11 with slight + // adjustments for p23. + // This has to be updated before p23 goes live with the configuration + // used at the network upgrade time. + let pubnet_fee_config = FeeConfiguration { + fee_per_instruction_increment: 25, + fee_per_disk_read_entry: 6250, + fee_per_write_entry: 10000, + fee_per_disk_read_1kb: 1786, + fee_per_write_1kb: 3500, + fee_per_historical_1kb: 16235, + fee_per_contract_event_1kb: 10000, + fee_per_transaction_size_1kb: 1624, + }; + let pubnet_persistent_rent_rate_denominator = 2103; + let pubnet_temp_rent_rate_denominator = 4206; + // This is a bit higher than the current network fee, it's an + // overestimate for the sake of providing a bit more conservative + // results in case if the state grows. + let fee_per_rent_1kb = 12000; + self.resources().estimate_fees( + &pubnet_fee_config, + fee_per_rent_1kb, + pubnet_persistent_rent_rate_denominator, + pubnet_temp_rent_rate_denominator, + ) + } + + /// Returns the budget object that provides the detailed CPU and memory + /// metering information recorded thus far. + /// + /// The budget metering resets before every top-level contract level + /// invocation. + /// + /// budget() may also be used to adjust the CPU and memory limits via the + /// `reset_` methods. + /// + /// Note, that unlike `resources()`/`fee()` this will always return some + /// value. If there was no contract call, then the resulting value will + /// correspond to metering any environment setup that has been made thus + /// far. + pub fn budget(&self) -> Budget { + Budget::new(self.env.host().budget_cloned()) + } + + /// Enforces custom resource limits for contract invocations in tests. + /// + /// When limit enforcement is enabled, for every contract invocation the + /// resource usage is checked against the provided limits, and if any of the + /// limits is exceeded, the contract invocation will result in a panic + /// that indicates which limits were exceeded. + /// + /// Limit enforcement is meant to provide an early warning sign that a + /// contract might be too resource heavy to run on a real network. If the + /// high resource usage is intentional and expected (e.g. for + /// experimentation), disable the enforcement via + /// `disable_resource_limits()`. + /// + /// By default, `InvocationResourceLimits::mainnet()` limits are enforced. + pub fn enforce_resource_limits(&self, limits: InvocationResourceLimits) { + self.env + .host() + .set_invocation_resource_limits(Some(limits)) + .unwrap(); + } + + /// Disables resource limit enforcement for contract invocations in tests. + /// + /// This may be useful for the experimental contracts that are still being + /// optimized. + pub fn disable_resource_limits(&self) { + self.env + .host() + .set_invocation_resource_limits(None) + .unwrap(); + } +} + +/// Predefined network invocation resource limits. +pub trait NetworkInvocationResourceLimits { + fn mainnet() -> Self; +} + +impl NetworkInvocationResourceLimits for InvocationResourceLimits { + /// Returns the invocation resource limits used on Stellar Mainnet. + /// + /// This is not pulling the values dynamically, so updating the SDK is + /// necessary to pick up the most recent values. + fn mainnet() -> Self { + InvocationResourceLimits { + instructions: 600_000_000, + mem_bytes: 41943040, + disk_read_entries: 100, + write_entries: 50, + ledger_entries: 100, + disk_read_bytes: 200000, + write_bytes: 132096, + contract_events_size_bytes: 16384, + max_contract_data_key_size_bytes: 250, + max_contract_data_entry_size_bytes: 65536, + max_contract_code_entry_size_bytes: 131072, + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs new file mode 100644 index 0000000..ba2446d --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs @@ -0,0 +1,145 @@ +#![cfg(any(test, feature = "testutils"))] + +use crate::{contract, contractimpl, xdr, Address, Env, Symbol, TryFromVal, Val, Vec}; + +#[doc(hidden)] +#[contract(crate_path = "crate")] +pub struct MockAuthContract; + +#[contractimpl(crate_path = "crate")] +impl MockAuthContract { + #[allow(non_snake_case)] + pub fn __check_auth(_signature_payload: Val, _signatures: Val, _auth_context: Val) {} +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MockAuth<'a> { + pub address: &'a Address, + pub invoke: &'a MockAuthInvoke<'a>, +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct MockAuthInvoke<'a> { + pub contract: &'a Address, + pub fn_name: &'a str, + pub args: Vec, + pub sub_invokes: &'a [MockAuthInvoke<'a>], +} + +impl<'a> From<&MockAuth<'a>> for xdr::SorobanAuthorizationEntry { + fn from(value: &MockAuth) -> Self { + let env = value.address.env(); + let curr_ledger = env.ledger().sequence(); + let max_entry_ttl = env.storage().max_ttl(); + Self { + root_invocation: value.invoke.into(), + credentials: xdr::SorobanCredentials::Address(xdr::SorobanAddressCredentials { + address: value.address.try_into().unwrap(), + nonce: env.with_generator(|mut g| g.nonce()), + signature_expiration_ledger: curr_ledger + max_entry_ttl, + signature: xdr::ScVal::Void, + }), + } + } +} + +impl<'a> From> for xdr::SorobanAuthorizationEntry { + fn from(value: MockAuth<'a>) -> Self { + (&value).into() + } +} + +impl<'a> From<&MockAuthInvoke<'a>> for xdr::SorobanAuthorizedInvocation { + fn from(value: &MockAuthInvoke<'a>) -> Self { + Self { + function: xdr::SorobanAuthorizedFunction::ContractFn(xdr::InvokeContractArgs { + contract_address: xdr::ScAddress::Contract(value.contract.contract_id()), + function_name: value.fn_name.try_into().unwrap(), + args: value.args.clone().try_into().unwrap(), + }), + sub_invocations: value + .sub_invokes + .iter() + .map(Into::<_>::into) + .collect::>() + .try_into() + .unwrap(), + } + } +} + +impl<'a> From> for xdr::SorobanAuthorizedInvocation { + fn from(value: MockAuthInvoke<'a>) -> Self { + (&value).into() + } +} + +/// Describes an authorized invocation tree from the perspective of a single +/// address. +/// +/// The authorized invocation tree for a given address is different from a +/// regular call tree: it only has nodes for the contract calls that called +/// `require_auth[_for_args]` for that address. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct AuthorizedInvocation { + /// Function that has called `require_auth`. + pub function: AuthorizedFunction, + /// Authorized invocations originating from `function`. + pub sub_invocations: std::vec::Vec, +} + +/// A single node in `AuthorizedInvocation` tree. +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum AuthorizedFunction { + /// Contract function defined by the contract address, function name and + /// `require_auth[_for_args]` arguments (these don't necessarily need to + /// match the actual invocation arguments). + Contract((Address, Symbol, Vec)), + /// Create contract host function with arguments specified as the respective + /// XDR. + CreateContractHostFn(xdr::CreateContractArgs), + /// Create contract host function with arguments specified as the respective + /// XDR. Supports passing constructor arguments. + CreateContractV2HostFn(xdr::CreateContractArgsV2), +} + +impl AuthorizedFunction { + pub fn from_xdr(env: &Env, v: &xdr::SorobanAuthorizedFunction) -> Self { + match v { + xdr::SorobanAuthorizedFunction::ContractFn(contract_fn) => { + let mut args = Vec::new(env); + for v in contract_fn.args.iter() { + args.push_back(Val::try_from_val(env, v).unwrap()); + } + Self::Contract(( + Address::try_from_val( + env, + &xdr::ScVal::Address(contract_fn.contract_address.clone()), + ) + .unwrap(), + Symbol::try_from_val(env, &contract_fn.function_name).unwrap(), + args, + )) + } + xdr::SorobanAuthorizedFunction::CreateContractHostFn(create_contract) => { + Self::CreateContractHostFn(create_contract.clone()) + } + xdr::SorobanAuthorizedFunction::CreateContractV2HostFn(create_contract) => { + Self::CreateContractV2HostFn(create_contract.clone()) + } + } + } +} + +impl AuthorizedInvocation { + pub fn from_xdr(env: &Env, v: &xdr::SorobanAuthorizedInvocation) -> Self { + Self { + function: AuthorizedFunction::from_xdr(env, &v.function), + sub_invocations: v + .sub_invocations + .iter() + .map(|si| AuthorizedInvocation::from_xdr(env, si)) + .collect(), + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs new file mode 100644 index 0000000..8d62833 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs @@ -0,0 +1,97 @@ +#![cfg(any(test, feature = "testutils"))] + +/// Sign implementations produce signatures for types that can be represented as +/// the MSG. +pub trait Sign { + type Signature; + type Error; + /// Sign produces a signature for MSGs. + fn sign(&self, m: MSG) -> Result; +} + +// TODO: Add a Verify interface and ed25519 implementation to counter the Sign +// interface. + +pub mod ed25519 { + use crate::xdr; + use xdr::{Limited, Limits, WriteXdr}; + + #[derive(Debug)] + pub enum Error { + XdrError(xdr::Error), + Ed25519SignatureError(ed25519_dalek::SignatureError), + ConversionError(E), + } + + impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::XdrError(e) => e.source(), + Self::Ed25519SignatureError(e) => e.source(), + Self::ConversionError(e) => e.source(), + } + } + } + + impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::XdrError(e) => write!(f, "{}", e), + Self::Ed25519SignatureError(e) => write!(f, "{}", e), + Self::ConversionError(e) => write!(f, "{}", e), + } + } + } + + impl From for Error { + fn from(e: xdr::Error) -> Self { + Error::XdrError(e) + } + } + + impl From for Error { + fn from(e: ed25519_dalek::SignatureError) -> Self { + Error::Ed25519SignatureError(e) + } + } + + pub use super::Sign; + + impl Sign for S + where + S: ed25519_dalek::Signer, + M: TryInto, + >::Error: std::error::Error, + { + type Error = Error<>::Error>; + type Signature = [u8; 64]; + fn sign(&self, m: M) -> Result { + let mut buf = Vec::::new(); + let val: xdr::ScVal = m.try_into().map_err(Self::Error::ConversionError)?; + val.write_xdr(&mut Limited::new(&mut buf, Limits::none()))?; + Ok(self.try_sign(&buf)?.to_bytes()) + } + } + + #[cfg(test)] + mod test { + use super::Sign; + use ed25519_dalek::SigningKey; + + #[test] + fn sign() { + let sk = SigningKey::from_bytes( + &hex::decode("5acc7253295dfc356c046297925a369f3d2762d00afdf2583ecbe92180b07c37") + .unwrap() + .try_into() + .unwrap(), + ); + let sig = sk.sign(128i64).unwrap(); + assert_eq!( + hex::encode(sig), + // Verified with https://go.dev/play/p/XiK8sOmvPsh + "a9b9dfac10bc1e5c8bc565e9515e5d086e3264b71bf4daf2c7340e1d10fae86e2563fa1d639ff153559a9710dfa270a9462fe87faa0e18a7a54a8a1a6151e909", + ); + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs new file mode 100644 index 0000000..41a9cc2 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs @@ -0,0 +1,41 @@ +use crate::{Env, IntoVal, Map, Val}; + +/// Test utilities for [`Persistent`][crate::storage::Persistent]. +pub trait Persistent { + /// Returns all data stored in persistent storage for the contract. + fn all(&self) -> Map; + + /// Gets the TTL for the persistent storage entry corresponding to the provided key. + /// + /// TTL is the number of ledgers left until the persistent entry is considered + /// expired, excluding the current ledger. + /// + /// Panics if there is no entry corresponding to the key, or if the entry has expired. + fn get_ttl>(&self, key: &K) -> u32; +} + +/// Test utilities for [`Temporary`][crate::storage::Temporary]. +pub trait Temporary { + /// Returns all data stored in temporary storage for the contract. + fn all(&self) -> Map; + + /// Gets the TTL for the temporary storage entry corresponding to the provided key. + /// + /// TTL is the number of ledgers left until the temporary entry is considered + /// non-existent, excluding the current ledger. + /// + /// Panics if there is no entry corresponding to the key. + fn get_ttl>(&self, key: &K) -> u32; +} + +/// Test utilities for [`Instance`][crate::storage::Instance]. +pub trait Instance { + /// Returns all data stored in Instance storage for the contract. + fn all(&self) -> Map; + + /// Gets the TTL for the current contract's instance entry. + /// + /// TTL is the number of ledgers left until the instance entry is considered + /// expired, excluding the current ledger. + fn get_ttl(&self) -> u32; +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/token.rs b/temp_sdk/soroban-sdk-26.0.1/src/token.rs new file mode 100644 index 0000000..c9d2bd4 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/token.rs @@ -0,0 +1,491 @@ +//! Token contains types for calling and accessing token contracts, including +//! the Stellar Asset Contract. +//! +//! See [`TokenInterface`] for the interface of token contracts such as the +//! Stellar Asset Contract. +//! +//! Use [`TokenClient`] for calling token contracts such as the Stellar Asset +//! Contract. + +use crate::{contracttrait, Address, Env, MuxedAddress, String}; + +// The interface below was copied from +// https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/native_contract/token/contract.rs +// at commit b3c188f48dec51a956c1380fb6fe92201a3f716b. +// +// Differences between this interface and the built-in contract +// 1. The return values here don't return Results. +// 2. The implementations have been replaced with a panic. +// 3. &Host type usage are replaced with Env + +#[doc(hidden)] +#[deprecated(note = "use TokenInterface")] +pub use TokenInterface as Interface; + +#[doc(hidden)] +#[deprecated(note = "use TokenClient")] +pub use TokenClient as Client; + +/// Interface for Token contracts, such as the Stellar Asset Contract. +/// +/// Defined by [SEP-41]. +/// +/// [SEP-41]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0041.md +/// +/// The token interface provides the following functionality. +/// +/// If a contract implementing the interface does not support some of the +/// functionality, it should return an error. +/// +/// The interface does not define any set of standard errors. Errors can be +/// defined by the implementing contract. +/// +/// ## Meta +/// +/// Tokens implementing the interface expose meta functions about the token: +/// - [`decimals`][Self::decimals] +/// - [`name`][Self::name] +/// - [`symbol`][Self::symbol] +/// +/// ## Balances +/// +/// Tokens track a balance for each address that holds the token. Tokens implementing the interface expose +/// a single function for getting the balance that an address holds: +/// - [`balance`][Self::balance] +/// +/// ## Transfers +/// +/// Tokens allow holders of the token to transfer tokens to other addresses. +/// Tokens implementing the interface expose a single function for doing so: +/// - [`transfer`][Self::transfer] +/// +/// ## Burning +/// +/// Tokens allow holders of the token to burn, i.e. dispose of, tokens without +/// transferring them to another holder. Tokens implementing the interface +/// expose a single function for doing so: +/// - [`burn`][Self::burn] +/// +/// ## Allowances +/// +/// Tokens can allow holders to permit others to transfer amounts from their +/// balance using the following functions. +/// - [`allowance`][Self::allowance] +/// - [`approve`][Self::approve] +/// - [`transfer_from`][Self::transfer_from] +/// - [`burn_from`][Self::burn_from] +/// +/// ## Minting +/// +/// There are no functions in the token interface for minting tokens. Minting is +/// an administrative function that can differ significantly from one token to +/// the next. +#[contracttrait( + crate_path = "crate", + spec_name = "TokenFnSpec", + spec_export = false, + args_name = "TokenArgs", + client_name = "TokenClient" +)] +pub trait TokenInterface { + /// Returns the allowance for `spender` to transfer from `from`. + /// + /// The amount returned is the amount that spender is allowed to transfer + /// out of from's balance. When the spender transfers amounts, the allowance + /// will be reduced by the amount transferred. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens to be drawn from. + /// * `spender` - The address spending the tokens held by `from`. + fn allowance(env: Env, from: Address, spender: Address) -> i128; + + /// Set the allowance by `amount` for `spender` to transfer/burn from + /// `from`. + /// + /// The amount set is the amount that spender is approved to transfer out of + /// from's balance. The spender will be allowed to transfer amounts, and + /// when an amount is transferred the allowance will be reduced by the + /// amount transferred. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens to be drawn from. + /// * `spender` - The address being authorized to spend the tokens held by + /// `from`. + /// * `amount` - The tokens to be made available to `spender`. + /// * `expiration_ledger` - The ledger number where this allowance expires. Cannot + /// be less than the current ledger number unless the amount is being set to 0. + /// An expired entry (where expiration_ledger < the current ledger number) + /// should be treated as a 0 amount allowance. + /// + /// # Events + /// + /// Emits an event with topics `["approve", from: Address, + /// spender: Address], data = [amount: i128, expiration_ledger: u32]` + fn approve(env: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32); + + /// Returns the balance of `id`. + /// + /// # Arguments + /// + /// * `id` - The address for which a balance is being queried. If the + /// address has no existing balance, returns 0. + fn balance(env: Env, id: Address) -> i128; + + /// Transfer `amount` from `from` to `to`. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens which will be + /// withdrawn from. + /// * `to` - The address which will receive the transferred tokens. + /// * `amount` - The amount of tokens to be transferred. + /// + /// # Events + /// + /// Emits an event with: + /// * topics `["transfer", from: Address, to: Address]` + /// * data `{ to_muxed_id: Option, amount: i128 }: Map` + /// + /// Legacy implementations may emit an event with: + /// * topics `["transfer", from: Address, to: Address]` + /// * data `amount: i128` + fn transfer(env: Env, from: Address, to: MuxedAddress, amount: i128); + + /// Transfer `amount` from `from` to `to`, consuming the allowance that + /// `spender` has on `from`'s balance. Authorized by spender + /// (`spender.require_auth()`). + /// + /// The spender will be allowed to transfer the amount from from's balance + /// if the amount is less than or equal to the allowance that the spender + /// has on the from's balance. The spender's allowance on from's balance + /// will be reduced by the amount. + /// + /// # Arguments + /// + /// * `spender` - The address authorizing the transfer, and having its + /// allowance consumed during the transfer. + /// * `from` - The address holding the balance of tokens which will be + /// withdrawn from. + /// * `to` - The address which will receive the transferred tokens. + /// * `amount` - The amount of tokens to be transferred. + /// + /// # Events + /// + /// Emits an event with topics `["transfer", from: Address, to: Address], + /// data = amount: i128` + fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128); + + /// Burn `amount` from `from`. + /// + /// Reduces from's balance by the amount, without transferring the balance + /// to another holder's balance. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens which will be + /// burned from. + /// * `amount` - The amount of tokens to be burned. + /// + /// # Events + /// + /// Emits an event with topics `["burn", from: Address], data = amount: + /// i128` + fn burn(env: Env, from: Address, amount: i128); + + /// Burn `amount` from `from`, consuming the allowance of `spender`. + /// + /// Reduces from's balance by the amount, without transferring the balance + /// to another holder's balance. + /// + /// The spender will be allowed to burn the amount from from's balance, if + /// the amount is less than or equal to the allowance that the spender has + /// on the from's balance. The spender's allowance on from's balance will be + /// reduced by the amount. + /// + /// # Arguments + /// + /// * `spender` - The address authorizing the burn, and having its allowance + /// consumed during the burn. + /// * `from` - The address holding the balance of tokens which will be + /// burned from. + /// * `amount` - The amount of tokens to be burned. + /// + /// # Events + /// + /// Emits an event with topics `["burn", from: Address], data = amount: + /// i128` + fn burn_from(env: Env, spender: Address, from: Address, amount: i128); + + /// Returns the number of decimals used to represent amounts of this token. + /// + /// # Panics + /// + /// If the contract has not yet been initialized. + fn decimals(env: Env) -> u32; + + /// Returns the name for this token. + /// + /// # Panics + /// + /// If the contract has not yet been initialized. + fn name(env: Env) -> String; + + /// Returns the symbol for this token. + /// + /// # Panics + /// + /// If the contract has not yet been initialized. + fn symbol(env: Env) -> String; +} + +/// Interface for admin capabilities for Token contracts, such as the Stellar +/// Asset Contract. +#[contracttrait( + crate_path = "crate", + spec_name = "StellarAssetFnSpec", + spec_export = false, + args_name = "StellarAssetArgs", + client_name = "StellarAssetClient" +)] +pub trait StellarAssetInterface { + /// Returns the allowance for `spender` to transfer from `from`. + /// + /// The amount returned is the amount that spender is allowed to transfer + /// out of from's balance. When the spender transfers amounts, the allowance + /// will be reduced by the amount transferred. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens to be drawn from. + /// * `spender` - The address spending the tokens held by `from`. + fn allowance(env: Env, from: Address, spender: Address) -> i128; + + /// Set the allowance by `amount` for `spender` to transfer/burn from + /// `from`. + /// + /// The amount set is the amount that spender is approved to transfer out of + /// from's balance. The spender will be allowed to transfer amounts, and + /// when an amount is transferred the allowance will be reduced by the + /// amount transferred. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens to be drawn from. + /// * `spender` - The address being authorized to spend the tokens held by + /// `from`. + /// * `amount` - The tokens to be made available to `spender`. + /// * `expiration_ledger` - The ledger number where this allowance expires. Cannot + /// be less than the current ledger number unless the amount is being set to 0. + /// An expired entry (where expiration_ledger < the current ledger number) + /// should be treated as a 0 amount allowance. + /// + /// # Events + /// + /// Emits an event with topics `["approve", from: Address, + /// spender: Address], data = [amount: i128, expiration_ledger: u32]` + fn approve(env: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32); + + /// Returns the balance of `id`. + /// + /// # Arguments + /// + /// * `id` - The address for which a balance is being queried. If the + /// address has no existing balance, returns 0. + fn balance(env: Env, id: Address) -> i128; + + /// Transfer `amount` from `from` to `to`. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens which will be + /// withdrawn from. + /// * `to` - The address which will receive the transferred tokens. + /// * `amount` - The amount of tokens to be transferred. + /// + /// # Events + /// + /// Emits an event with: + /// * topics `["transfer", from: Address, to: Address]` + /// * data `{ to_muxed_id: Option, amount: i128 }: Map` + /// + /// Legacy implementations may emit an event with: + /// * topics `["transfer", from: Address, to: Address]` + /// * data `amount: i128` + fn transfer(env: Env, from: Address, to: MuxedAddress, amount: i128); + + /// Transfer `amount` from `from` to `to`, consuming the allowance that + /// `spender` has on `from`'s balance. Authorized by spender + /// (`spender.require_auth()`). + /// + /// The spender will be allowed to transfer the amount from from's balance + /// if the amount is less than or equal to the allowance that the spender + /// has on the from's balance. The spender's allowance on from's balance + /// will be reduced by the amount. + /// + /// # Arguments + /// + /// * `spender` - The address authorizing the transfer, and having its + /// allowance consumed during the transfer. + /// * `from` - The address holding the balance of tokens which will be + /// withdrawn from. + /// * `to` - The address which will receive the transferred tokens. + /// * `amount` - The amount of tokens to be transferred. + /// + /// # Events + /// + /// Emits an event with topics `["transfer", from: Address, to: Address], + /// data = amount: i128` + fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128); + + /// Burn `amount` from `from`. + /// + /// Reduces from's balance by the amount, without transferring the balance + /// to another holder's balance. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance of tokens which will be + /// burned from. + /// * `amount` - The amount of tokens to be burned. + /// + /// # Events + /// + /// Emits an event with topics `["burn", from: Address], data = amount: + /// i128` + fn burn(env: Env, from: Address, amount: i128); + + /// Burn `amount` from `from`, consuming the allowance of `spender`. + /// + /// Reduces from's balance by the amount, without transferring the balance + /// to another holder's balance. + /// + /// The spender will be allowed to burn the amount from from's balance, if + /// the amount is less than or equal to the allowance that the spender has + /// on the from's balance. The spender's allowance on from's balance will be + /// reduced by the amount. + /// + /// # Arguments + /// + /// * `spender` - The address authorizing the burn, and having its allowance + /// consumed during the burn. + /// * `from` - The address holding the balance of tokens which will be + /// burned from. + /// * `amount` - The amount of tokens to be burned. + /// + /// # Events + /// + /// Emits an event with topics `["burn", from: Address], data = amount: + /// i128` + fn burn_from(env: Env, spender: Address, from: Address, amount: i128); + + /// Returns the number of decimals used to represent amounts of this token. + /// + /// # Panics + /// + /// If the contract has not yet been initialized. + fn decimals(env: Env) -> u32; + + /// Returns the name for this token. + /// + /// # Panics + /// + /// If the contract has not yet been initialized. + fn name(env: Env) -> String; + + /// Returns the symbol for this token. + /// + /// # Panics + /// + /// If the contract has not yet been initialized. + fn symbol(env: Env) -> String; + + /// Sets the administrator to the specified address `new_admin`. + /// + /// # Arguments + /// + /// * `new_admin` - The address which will henceforth be the administrator + /// of this token contract. + /// + /// # Events + /// + /// Emits an event with topics `["set_admin", admin: Address], data = + /// [new_admin: Address]` + fn set_admin(env: Env, new_admin: Address); + + /// Returns the admin of the contract. + /// + /// # Panics + /// + /// If the admin is not set. + fn admin(env: Env) -> Address; + + /// Sets whether the account is authorized to use its balance. If + /// `authorized` is true, `id` should be able to use its balance. + /// + /// # Arguments + /// + /// * `id` - The address being (de-)authorized. + /// * `authorize` - Whether or not `id` can use its balance. + /// + /// # Events + /// + /// Emits an event with topics `["set_authorized", id: Address], data = + /// [authorize: bool]` + fn set_authorized(env: Env, id: Address, authorize: bool); + + /// Returns true if `id` is authorized to use its balance. + /// + /// # Arguments + /// + /// * `id` - The address for which token authorization is being checked. + fn authorized(env: Env, id: Address) -> bool; + + /// Mints `amount` to `to`. + /// + /// # Arguments + /// + /// * `to` - The address which will receive the minted tokens. + /// * `amount` - The amount of tokens to be minted. + /// + /// # Events + /// + /// Emits an event with topics `["mint", to: Address], data + /// = amount: i128` + fn mint(env: Env, to: Address, amount: i128); + + /// Clawback `amount` from `from` account. `amount` is burned in the + /// clawback process. + /// + /// # Arguments + /// + /// * `from` - The address holding the balance from which the clawback will + /// take tokens. + /// * `amount` - The amount of tokens to be clawed back. + /// + /// # Events + /// + /// Emits an event with topics `["clawback", admin: Address, to: Address], + /// data = amount: i128` + fn clawback(env: Env, from: Address, amount: i128); + + /// Creates this contract asset's unlimited trustline for the provided + /// address. + /// + /// This is a no-op if the input address is a C-address, or if the + /// provided G-address already has the respective trustline. + /// + /// If the trustline is actually created, this will require authorization + /// from `addr` (i.e. `addr.require_auth` will be called). + /// + /// # Arguments + /// + /// * `addr` - The address for which a trustline will be created. + /// + /// # Panics + /// + /// Panics during trustline creation if the asset issuer does not exist, + /// or when a new trustline cannot be created. + fn trust(env: Env, addr: Address); +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs b/temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs new file mode 100644 index 0000000..51f94d9 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs @@ -0,0 +1,58 @@ +//! TryFromValForContractFn is an internal trait that is used by code generated +//! for the export of contract functions. The generated code calls the trait to +//! convert incoming Val's into their respective SDK types. +//! +//! The trait has a blanket implementation for all types that already implement +//! TryFromVal<_, Val>. +//! +//! The trait exists primarily to allow some special types, e.g. +//! [`crate::crypto::Hash`], to be used as inputs to contract functions without +//! otherwise being creatable from a Val via the public TryFromVal trait, and +//! therefore not storeable. +//! +//! For types that can be used and converted everywhere, implementing TryFromVal +//! is most appropriate. For types that should only be used and converted to as +//! part of contract function invocation, then this trait is appropriate. +//! +//! When the `experimental_spec_shaking_v2` feature is enabled, this trait also +//! calls `SpecShakingMarker::spec_shaking_marker()` to ensure that type specs +//! are included in the WASM when types are used at external boundaries. + +use crate::{env::internal::Env, Error, TryFromVal}; +use core::fmt::Debug; + +#[doc(hidden)] +#[deprecated( + note = "TryFromValForContractFn is an internal trait and is not safe to use or implement" +)] +pub trait TryFromValForContractFn: Sized { + type Error: Debug + Into; + fn try_from_val_for_contract_fn(env: &E, v: &V) -> Result; +} + +#[cfg(feature = "experimental_spec_shaking_v2")] +#[doc(hidden)] +#[allow(deprecated)] +impl TryFromValForContractFn for U +where + U: TryFromVal + crate::SpecShakingMarker, +{ + type Error = U::Error; + fn try_from_val_for_contract_fn(e: &E, v: &T) -> Result { + U::spec_shaking_marker(); + U::try_from_val(e, v) + } +} + +#[cfg(not(feature = "experimental_spec_shaking_v2"))] +#[doc(hidden)] +#[allow(deprecated)] +impl TryFromValForContractFn for U +where + U: TryFromVal, +{ + type Error = U::Error; + fn try_from_val_for_contract_fn(e: &E, v: &T) -> Result { + U::try_from_val(e, v) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/tuple.rs b/temp_sdk/soroban-sdk-26.0.1/src/tuple.rs new file mode 100644 index 0000000..066021a --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/tuple.rs @@ -0,0 +1,73 @@ +//! This module contains conversion helpers for tuple + +use crate::{vec, ConversionError, Env, IntoVal, Topics, TryFromVal, Val, Vec}; + +// Note that the way that this conversion of tuple to Vec is written results in a need for any +// supported type to support converting from `&&` (double-ref) to `Val`. This means values that +// convert to `Val` need to have an impl of TryFromVal converting not only from their owned value +// (which converts from a ref of that owned value), but from a & value (which converts from a +// double ref &&). +// +// This is why you'll see TryFromVal impls from &values, not just owned values. + +impl TryFromVal for Vec { + type Error = ConversionError; + + fn try_from_val(env: &Env, _v: &()) -> Result { + Ok(Vec::::new(env)) + } +} + +macro_rules! impl_into_vec_for_tuple { + ( $($typ:ident $idx:tt)* ) => { + impl<$($typ),*> TryFromVal for Vec + where + $($typ: IntoVal),* + { + type Error = ConversionError; + fn try_from_val(env: &Env, v: &($($typ,)*)) -> Result { + Ok(vec![&env, $(v.$idx.into_val(env), )*]) + } + } + }; +} +impl_into_vec_for_tuple! { T0 0 } +impl_into_vec_for_tuple! { T0 0 T1 1 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 } +impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 } + +macro_rules! impl_topics_for_tuple { + ( $($typ:ident $idx:tt)* ) => { + impl<$($typ),*> Topics for ($($typ,)*) + where + $($typ: IntoVal),* + { + } + }; +} + +// 0 topics +impl Topics for () {} +// 1-13 topics +impl_topics_for_tuple! { T0 0 } +impl_topics_for_tuple! { T0 0 T1 1 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 } +impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 } diff --git a/temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs b/temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs new file mode 100644 index 0000000..73787cd --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs @@ -0,0 +1,96 @@ +use core::convert::Infallible; + +pub trait UnwrapOptimized { + type Output; + fn unwrap_optimized(self) -> Self::Output; + fn expect_optimized(self, msg: &'static str) -> Self::Output; +} + +impl UnwrapOptimized for Option { + type Output = T; + + #[inline(always)] + fn unwrap_optimized(self) -> Self::Output { + #[cfg(target_family = "wasm")] + match self { + Some(t) => t, + None => core::arch::wasm32::unreachable(), + } + #[cfg(not(target_family = "wasm"))] + self.unwrap() + } + + #[inline(always)] + fn expect_optimized(self, _msg: &'static str) -> Self::Output { + #[cfg(target_family = "wasm")] + match self { + Some(t) => t, + None => core::arch::wasm32::unreachable(), + } + #[cfg(not(target_family = "wasm"))] + self.expect(_msg) + } +} + +impl UnwrapOptimized for Result { + type Output = T; + + #[inline(always)] + fn unwrap_optimized(self) -> Self::Output { + #[cfg(target_family = "wasm")] + match self { + Ok(t) => t, + Err(_) => core::arch::wasm32::unreachable(), + } + #[cfg(not(target_family = "wasm"))] + self.unwrap() + } + + #[inline(always)] + fn expect_optimized(self, _msg: &'static str) -> Self::Output { + #[cfg(target_family = "wasm")] + match self { + Ok(t) => t, + Err(_) => core::arch::wasm32::unreachable(), + } + #[cfg(not(target_family = "wasm"))] + self.expect(_msg) + } +} + +pub trait UnwrapInfallible { + type Output; + fn unwrap_infallible(self) -> Self::Output; +} + +impl UnwrapInfallible for Result { + type Output = T; + + fn unwrap_infallible(self) -> Self::Output { + match self { + Ok(ok) => ok, + // In the following `Err(never)` branch we convert a type from + // `Infallible` to `!`. Both of these are empty types and are + // essentially synonyms in rust, they differ only due to historical + // reasons that will eventually be eliminated. `Infallible` is a + // version we can put in a structure, and `!` is one that gets some + // special control-flow treatments. + // + // Specifically: the type `!` of the resulting expression will be + // considered an acceptable inhabitant of any type -- including + // `Self::Output` -- since it's an impossible path to execute, this + // is considered a harmless convenience in the type system, a bit + // like defining zero-divided-by-anything as zero. + // + // We could also write an infinite `loop {}` here or + // `unreachable!()` or similar expressions of type `!`, but + // destructuring the `never` variable into an empty set of cases is + // the most honest since it's statically checked to _be_ infallible, + // not just an assertion of our hopes.) + + // This allow and the Err can be removed once 1.82 becomes stable + #[allow(unreachable_patterns)] + Err(never) => match never {}, + } + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/vec.rs b/temp_sdk/soroban-sdk-26.0.1/src/vec.rs new file mode 100644 index 0000000..226c935 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/vec.rs @@ -0,0 +1,2000 @@ +use core::{ + borrow::Borrow, + cmp::Ordering, + convert::Infallible, + fmt::Debug, + iter::FusedIterator, + marker::PhantomData, + ops::{Bound, RangeBounds}, +}; + +use crate::{ + iter::{UnwrappedEnumerable, UnwrappedIter}, + unwrap::{UnwrapInfallible, UnwrapOptimized}, +}; + +use super::{ + env::internal::{Env as _, EnvBase as _, VecObject}, + ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, +}; + +#[cfg(doc)] +use crate::{storage::Storage, Bytes, BytesN, Map}; + +/// Create a [Vec] with the given items. +/// +/// The first argument in the list must be a reference to an [Env], then the +/// items follow. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{Env, vec}; +/// +/// let env = Env::default(); +/// let vec = vec![&env, 0, 1, 2, 3]; +/// assert_eq!(vec.len(), 4); +/// ``` +#[macro_export] +macro_rules! vec { + ($env:expr $(,)?) => { + $crate::Vec::new($env) + }; + ($env:expr, $($x:expr),+ $(,)?) => { + $crate::Vec::from_array($env, [$($x),+]) + }; +} + +/// Vec is a sequential and indexable growable collection type. +/// +/// Values are stored in the environment and are available to contract through +/// the functions defined on Vec. Values stored in the Vec are transmitted to +/// the environment as [Val]s, and when retrieved from the Vec are +/// transmitted back and converted from [Val] back into their type. +/// +/// The values in a Vec are not guaranteed to be of type `T` and conversion will +/// fail if they are not. Most functions on Vec have a `try_` variation that +/// returns a `Result` that will be `Err` if the conversion fails. Functions +/// that are not prefixed with `try_` will panic if conversion fails. +/// +/// There are some cases where this lack of guarantee is important: +/// +/// - When storing a Vec that has been provided externally as a contract +/// function argument, be aware there is no guarantee that all items in the Vec +/// will be of type `T`. It may be necessary to validate all values, either +/// before storing, or when loading with `try_` variation functions. +/// +/// - When accessing and iterating over a Vec that has been provided externally +/// as a contract function input, and the contract needs to be resilient to +/// failure, use the `try_` variation functions. +/// +/// Functions with an `_unchecked` suffix will panic if called with indexes that +/// are out-of-bounds. +/// +/// To store `u8`s and binary data, use [Bytes]/[BytesN] instead. +/// +/// Vec values can be stored as [Storage], or in other types like [Vec], [Map], +/// etc. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{vec, Env}; +/// +/// let env = Env::default(); +/// let vec = vec![&env, 0, 1, 2, 3]; +/// assert_eq!(vec.len(), 4); +/// ``` +pub struct Vec { + env: Env, + obj: VecObject, + _t: PhantomData, +} + +impl Clone for Vec { + fn clone(&self) -> Self { + Self { + env: self.env.clone(), + obj: self.obj, + _t: self._t, + } + } +} + +impl Eq for Vec where T: IntoVal + TryFromVal {} + +impl PartialEq for Vec +where + T: IntoVal + TryFromVal, +{ + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for Vec +where + T: IntoVal + TryFromVal, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Ord for Vec +where + T: IntoVal + TryFromVal, +{ + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + #[cfg(not(target_family = "wasm"))] + if !self.env.is_same_env(&other.env) { + return ScVal::from(self).cmp(&ScVal::from(other)); + } + let v = self + .env + .obj_cmp(self.obj.to_val(), other.obj.to_val()) + .unwrap_infallible(); + v.cmp(&0) + } +} + +impl Debug for Vec +where + T: IntoVal + TryFromVal + Debug + Clone, + T::Error: Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Vec(")?; + let mut iter = self.try_iter(); + if let Some(x) = iter.next() { + write!(f, "{:?}", x)?; + } + for x in iter { + write!(f, ", {:?}", x)?; + } + write!(f, ")")?; + Ok(()) + } +} + +impl TryFromVal> for Vec { + type Error = Infallible; + + fn try_from_val(env: &Env, v: &Vec) -> Result { + Ok(unsafe { Vec::unchecked_new(env.clone(), v.obj) }) + } +} + +// This conflicts with the previous definition unless we add the spurious &, +// which is not .. great. Maybe don't define this particular blanket, or add +// a to_other() method? +impl TryFromVal> for Vec { + type Error = Infallible; + + fn try_from_val(env: &Env, v: &&Vec) -> Result { + Ok(unsafe { Vec::unchecked_new(env.clone(), v.obj) }) + } +} + +impl TryFromVal for Vec +where + T: IntoVal + TryFromVal, +{ + type Error = Infallible; + + #[inline(always)] + fn try_from_val(env: &Env, obj: &VecObject) -> Result { + Ok(unsafe { Vec::::unchecked_new(env.clone(), *obj) }) + } +} + +impl TryFromVal for Vec +where + T: IntoVal + TryFromVal, +{ + type Error = ConversionError; + + #[inline(always)] + fn try_from_val(env: &Env, val: &Val) -> Result { + Ok(VecObject::try_from_val(env, val)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +impl TryFromVal> for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &Vec) -> Result { + Ok(v.to_val()) + } +} + +impl TryFromVal> for Val { + type Error = ConversionError; + + fn try_from_val(_env: &Env, v: &&Vec) -> Result { + Ok(v.to_val()) + } +} + +impl From> for Val +where + T: IntoVal + TryFromVal, +{ + #[inline(always)] + fn from(v: Vec) -> Self { + v.obj.into() + } +} + +impl From> for VecObject +where + T: IntoVal + TryFromVal, +{ + #[inline(always)] + fn from(v: Vec) -> Self { + v.obj + } +} + +#[cfg(not(target_family = "wasm"))] +use super::xdr::{ScVal, ScVec, VecM}; + +#[cfg(not(target_family = "wasm"))] +impl From<&Vec> for ScVal { + fn from(v: &Vec) -> Self { + // This conversion occurs only in test utilities, and theoretically all + // values should convert to an ScVal because the Env won't let the host + // type to exist otherwise, unwrapping. Even if there are edge cases + // that don't, this is a trade off for a better test developer + // experience. + ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From<&Vec> for ScVec { + fn from(v: &Vec) -> Self { + if let ScVal::Vec(Some(vec)) = ScVal::try_from(v).unwrap() { + vec + } else { + panic!("expected ScVec") + } + } +} + +#[cfg(not(target_family = "wasm"))] +impl From> for VecM { + fn from(v: Vec) -> Self { + ScVec::from(v).0 + } +} + +#[cfg(not(target_family = "wasm"))] +impl From> for ScVal { + fn from(v: Vec) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl From> for ScVec { + fn from(v: Vec) -> Self { + (&v).into() + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Vec +where + T: IntoVal + TryFromVal, +{ + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVal) -> Result { + Ok(VecObject::try_from_val(env, &Val::try_from_val(env, val)?)? + .try_into_val(env) + .unwrap_infallible()) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal for Vec +where + T: IntoVal + TryFromVal, +{ + type Error = ConversionError; + fn try_from_val(env: &Env, val: &ScVec) -> Result { + ScVal::Vec(Some(val.clone())).try_into_val(env) + } +} + +#[cfg(not(target_family = "wasm"))] +impl TryFromVal> for Vec +where + T: IntoVal + TryFromVal, +{ + type Error = ConversionError; + fn try_from_val(env: &Env, val: &VecM) -> Result { + ScVec(val.clone()).try_into_val(env) + } +} + +impl Vec { + #[inline(always)] + pub(crate) unsafe fn unchecked_new(env: Env, obj: VecObject) -> Self { + Self { + env, + obj, + _t: PhantomData, + } + } + + pub fn env(&self) -> &Env { + &self.env + } + + pub fn as_val(&self) -> &Val { + self.obj.as_val() + } + + pub fn to_val(&self) -> Val { + self.obj.to_val() + } + + pub fn as_object(&self) -> &VecObject { + &self.obj + } + + pub fn to_object(&self) -> VecObject { + self.obj + } + + pub fn to_vals(&self) -> Vec { + unsafe { Vec::::unchecked_new(self.env().clone(), self.obj) } + } +} + +impl Vec +where + T: IntoVal + TryFromVal, +{ + /// Create an empty Vec. + #[inline(always)] + pub fn new(env: &Env) -> Vec { + unsafe { Self::unchecked_new(env.clone(), env.vec_new().unwrap_infallible()) } + } + + /// Create a Vec from the array of items. + #[inline(always)] + pub fn from_array(env: &Env, items: [T; N]) -> Vec { + let mut tmp: [Val; N] = [Val::VOID.to_val(); N]; + for (dst, src) in tmp.iter_mut().zip(items.iter()) { + *dst = src.into_val(env) + } + let vec = env.vec_new_from_slice(&tmp).unwrap_infallible(); + unsafe { Self::unchecked_new(env.clone(), vec) } + } + + /// Create a Vec from an iterator of items. + /// + /// This provides FromIterator-like functionality but requires an Env parameter. + /// + /// Note: This function iteratively adds each item one at a time, making a call to the Soroban + /// environment for each item making it inefficient for joining two [`Vec`]s. Use + /// [`Vec::append`] to join two [`Vec`]s. + /// + /// ### Examples + /// + /// ``` + /// use soroban_sdk::{Env, Vec}; + /// + /// let env = Env::default(); + /// let items = vec![1, 2, 3, 4]; + /// let vec = Vec::from_iter(&env, items.into_iter()); + /// assert_eq!(vec.len(), 4); + /// ``` + #[inline(always)] + pub fn from_iter>(env: &Env, iter: I) -> Vec { + let mut vec = Self::new(env); + vec.extend(iter); + vec + } + + /// Create a Vec from the slice of items. + #[inline(always)] + pub fn from_slice(env: &Env, items: &[T]) -> Vec + where + T: Clone, + { + let mut vec = Vec::new(env); + vec.extend_from_slice(items); + vec + } + + /// Returns the item at the position or None if out-of-bounds. + /// + /// ### Panics + /// + /// If the value at the position cannot be converted to type T. + #[inline(always)] + pub fn get(&self, i: u32) -> Option { + self.try_get(i).unwrap_optimized() + } + + /// Returns the item at the position or None if out-of-bounds. + /// + /// ### Errors + /// + /// If the value at the position cannot be converted to type T. + #[inline(always)] + pub fn try_get(&self, i: u32) -> Result, T::Error> { + if i < self.len() { + self.try_get_unchecked(i).map(|val| Some(val)) + } else { + Ok(None) + } + } + + /// Returns the item at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + /// + /// If the value at the position cannot be converted to type T. + #[inline(always)] + pub fn get_unchecked(&self, i: u32) -> T { + self.try_get_unchecked(i).unwrap_optimized() + } + + /// Returns the item at the position. + /// + /// ### Errors + /// + /// If the value at the position cannot be converted to type T. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn try_get_unchecked(&self, i: u32) -> Result { + let env = self.env(); + let val = env.vec_get(self.obj, i.into()).unwrap_infallible(); + T::try_from_val(env, &val) + } + + /// Sets the item at the position with new value. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn set(&mut self, i: u32, v: T) { + let env = self.env(); + self.obj = env + .vec_put(self.obj, i.into(), v.into_val(env)) + .unwrap_infallible(); + } + + /// Removes the item at the position. + /// + /// Returns `None` if out-of-bounds. + #[inline(always)] + pub fn remove(&mut self, i: u32) -> Option<()> { + if i < self.len() { + self.remove_unchecked(i); + Some(()) + } else { + None + } + } + + /// Removes the item at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn remove_unchecked(&mut self, i: u32) { + let env = self.env(); + self.obj = env.vec_del(self.obj, i.into()).unwrap_infallible(); + } + + /// Adds the item to the front. + /// + /// Increases the length by one, shifts all items up by one, and puts the + /// item in the first position. + #[inline(always)] + pub fn push_front(&mut self, x: T) { + let env = self.env(); + self.obj = env + .vec_push_front(self.obj, x.into_val(env)) + .unwrap_infallible(); + } + + /// Removes and returns the first item or None if empty. + /// + /// ### Panics + /// + /// If the value at the first position cannot be converted to type T. + #[inline(always)] + pub fn pop_front(&mut self) -> Option { + self.try_pop_front().unwrap_optimized() + } + + /// Removes and returns the first item or None if empty. + /// + /// ### Errors + /// + /// If the value at the first position cannot be converted to type T. + #[inline(always)] + pub fn try_pop_front(&mut self) -> Result, T::Error> { + if self.is_empty() { + Ok(None) + } else { + self.try_pop_front_unchecked().map(|val| Some(val)) + } + } + + /// Removes and returns the first item. + /// + /// ### Panics + /// + /// If the vec is empty. + /// + /// If the value at the first position cannot be converted to type T. + #[inline(always)] + pub fn pop_front_unchecked(&mut self) -> T { + self.try_pop_front_unchecked().unwrap_optimized() + } + + /// Removes and returns the first item. + /// + /// ### Errors + /// + /// If the value at the first position cannot be converted to type T. + /// + /// ### Panics + /// + /// If the vec is empty. + #[inline(always)] + pub fn try_pop_front_unchecked(&mut self) -> Result { + let last = self.try_first_unchecked()?; + let env = self.env(); + self.obj = env.vec_pop_front(self.obj).unwrap_infallible(); + Ok(last) + } + + /// Adds the item to the back. + /// + /// Increases the length by one and puts the item in the last position. + #[inline(always)] + pub fn push_back(&mut self, x: T) { + let env = self.env(); + self.obj = env + .vec_push_back(self.obj, x.into_val(env)) + .unwrap_infallible(); + } + + /// Removes and returns the last item or None if empty. + /// + /// ### Panics + /// + /// If the value at the last position cannot be converted to type T. + #[inline(always)] + pub fn pop_back(&mut self) -> Option { + self.try_pop_back().unwrap_optimized() + } + + /// Removes and returns the last item or None if empty. + /// + /// ### Errors + /// + /// If the value at the last position cannot be converted to type T. + #[inline(always)] + pub fn try_pop_back(&mut self) -> Result, T::Error> { + if self.is_empty() { + Ok(None) + } else { + self.try_pop_back_unchecked().map(|val| Some(val)) + } + } + + /// Removes and returns the last item. + /// + /// ### Panics + /// + /// If the vec is empty. + /// + /// If the value at the last position cannot be converted to type T. + #[inline(always)] + pub fn pop_back_unchecked(&mut self) -> T { + self.try_pop_back_unchecked().unwrap_optimized() + } + + /// Removes and returns the last item. + /// + /// ### Errors + /// + /// If the value at the last position cannot be converted to type T. + /// + /// ### Panics + /// + /// If the vec is empty. + #[inline(always)] + pub fn try_pop_back_unchecked(&mut self) -> Result { + let last = self.try_last_unchecked()?; + let env = self.env(); + self.obj = env.vec_pop_back(self.obj).unwrap_infallible(); + Ok(last) + } + + /// Returns the first item or None if empty. + /// + /// ### Panics + /// + /// If the value at the first position cannot be converted to type T. + #[inline(always)] + pub fn first(&self) -> Option { + self.try_first().unwrap_optimized() + } + + /// Returns the first item or None if empty. + /// + /// ### Errors + /// + /// If the value at the first position cannot be converted to type T. + #[inline(always)] + pub fn try_first(&self) -> Result, T::Error> { + if self.is_empty() { + Ok(None) + } else { + self.try_first_unchecked().map(|val| Some(val)) + } + } + + /// Returns the first item. + /// + /// ### Panics + /// + /// If the vec is empty. + /// + /// If the value at the first position cannot be converted to type T. + #[inline(always)] + pub fn first_unchecked(&self) -> T { + self.try_first_unchecked().unwrap_optimized() + } + + /// Returns the first item. + /// + /// ### Errors + /// + /// If the value at the first position cannot be converted to type T. + /// + /// ### Panics + /// + /// If the vec is empty. + #[inline(always)] + pub fn try_first_unchecked(&self) -> Result { + let env = &self.env; + let val = env.vec_front(self.obj).unwrap_infallible(); + T::try_from_val(env, &val) + } + + /// Returns the last item or None if empty. + /// + /// ### Panics + /// + /// If the value at the last position cannot be converted to type T. + #[inline(always)] + pub fn last(&self) -> Option { + self.try_last().unwrap_optimized() + } + + /// Returns the last item or None if empty. + /// + /// ### Errors + /// + /// If the value at the last position cannot be converted to type T. + #[inline(always)] + pub fn try_last(&self) -> Result, T::Error> { + if self.is_empty() { + Ok(None) + } else { + self.try_last_unchecked().map(|val| Some(val)) + } + } + + /// Returns the last item. + /// + /// ### Panics + /// + /// If the vec is empty. + /// + /// If the value at the last position cannot be converted to type T. + #[inline(always)] + pub fn last_unchecked(&self) -> T { + self.try_last_unchecked().unwrap_optimized() + } + + /// Returns the last item. + /// + /// ### Errors + /// + /// If the value at the last position cannot be converted to type T. + /// + /// ### Panics + /// + /// If the vec is empty. + #[inline(always)] + pub fn try_last_unchecked(&self) -> Result { + let env = self.env(); + let val = env.vec_back(self.obj).unwrap_infallible(); + T::try_from_val(env, &val) + } + + /// Inserts an item at the position. + /// + /// ### Panics + /// + /// If the position is out-of-bounds. + #[inline(always)] + pub fn insert(&mut self, i: u32, x: T) { + let env = self.env(); + self.obj = env + .vec_insert(self.obj, i.into(), x.into_val(env)) + .unwrap_infallible(); + } + + /// Append the items. + #[inline(always)] + pub fn append(&mut self, other: &Vec) { + let env = self.env(); + self.obj = env.vec_append(self.obj, other.obj).unwrap_infallible(); + } + + /// Extend with the items in the array. + #[inline(always)] + pub fn extend_from_array(&mut self, items: [T; N]) { + self.append(&Self::from_array(&self.env, items)) + } + + /// Extend with the items in the slice. + #[inline(always)] + pub fn extend_from_slice(&mut self, items: &[T]) + where + T: Clone, + { + for item in items { + self.push_back(item.clone()); + } + } +} + +impl Vec { + /// Returns a subset of the bytes as defined by the start and end bounds of + /// the range. + /// + /// ### Panics + /// + /// If the range is out-of-bounds. + #[must_use] + pub fn slice(&self, r: impl RangeBounds) -> Self { + let start_bound = match r.start_bound() { + Bound::Included(s) => *s, + Bound::Excluded(s) => s + .checked_add(1) + .expect_optimized("attempt to add with overflow"), + Bound::Unbounded => 0, + }; + let end_bound = match r.end_bound() { + Bound::Included(s) => s + .checked_add(1) + .expect_optimized("attempt to add with overflow"), + Bound::Excluded(s) => *s, + Bound::Unbounded => self.len(), + }; + let env = self.env(); + let obj = env + .vec_slice(self.obj, start_bound.into(), end_bound.into()) + .unwrap_infallible(); + unsafe { Self::unchecked_new(env.clone(), obj) } + } + + /// Returns copy of the vec shuffled using the NOT-SECURE PRNG. + /// + /// In tests, must be called from within a running contract. + /// + /// # Warning + /// + /// **The pseudo-random generator used to perform the shuffle is not + /// suitable for security-sensitive work.** + pub fn shuffle(&mut self) { + let env = self.env(); + env.prng().shuffle(self); + } + + /// Returns copy of the vec shuffled using the NOT-SECURE PRNG. + /// + /// In tests, must be called from within a running contract. + /// + /// # Warning + /// + /// **The pseudo-random generator used to perform the shuffle is not + /// suitable for security-sensitive work.** + #[must_use] + pub fn to_shuffled(&self) -> Self { + let mut copy = self.clone(); + copy.shuffle(); + copy + } + + /// Returns true if the vec is empty and contains no items. + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of items in the vec. + #[inline(always)] + pub fn len(&self) -> u32 { + self.env.vec_len(self.obj).unwrap_infallible().into() + } +} + +impl Vec +where + T: IntoVal, +{ + /// Returns true if the Vec contains the item. + #[inline(always)] + pub fn contains(&self, item: impl Borrow) -> bool { + let env = self.env(); + let val = item.borrow().into_val(env); + !env.vec_first_index_of(self.obj, val) + .unwrap_infallible() + .is_void() + } + + /// Returns the index of the first occurrence of the item. + /// + /// If the item cannot be found [None] is returned. + #[inline(always)] + pub fn first_index_of(&self, item: impl Borrow) -> Option { + let env = self.env(); + let val = item.borrow().into_val(env); + env.vec_first_index_of(self.obj, val) + .unwrap_infallible() + .try_into_val(env) + .unwrap() + } + + /// Returns the index of the last occurrence of the item. + /// + /// If the item cannot be found [None] is returned. + #[inline(always)] + pub fn last_index_of(&self, item: impl Borrow) -> Option { + let env = self.env(); + let val = item.borrow().into_val(env); + env.vec_last_index_of(self.obj, val) + .unwrap_infallible() + .try_into_val(env) + .unwrap() + } + + /// Returns the index of an occurrence of the item in an already sorted + /// [Vec], or the index of where the item can be inserted to keep the [Vec] + /// sorted. + /// + /// If the item is found, [Result::Ok] is returned containing the index of + /// the item. + /// + /// If the item is not found, [Result::Err] is returned containing the index + /// of where the item could be inserted to retain the sorted ordering. + #[inline(always)] + pub fn binary_search(&self, item: impl Borrow) -> Result { + let env = self.env(); + let val = item.borrow().into_val(env); + let high_low = env.vec_binary_search(self.obj, val).unwrap_infallible(); + let high: u32 = (high_low >> u32::BITS) as u32; + let low: u32 = high_low as u32; + if high == 1 { + Ok(low) + } else { + Err(low) + } + } +} + +impl Vec> +where + T: IntoVal + TryFromVal, + T: Clone, +{ + #[inline(always)] + pub fn concat(&self) -> Vec { + let mut concatenated = vec![self.env()]; + for vec in self.iter() { + concatenated.append(&vec); + } + concatenated + } +} + +impl IntoIterator for Vec +where + T: IntoVal + TryFromVal, +{ + type Item = T; + type IntoIter = UnwrappedIter, T, T::Error>; + + fn into_iter(self) -> Self::IntoIter { + VecTryIter::new(self).unwrapped() + } +} + +impl IntoIterator for &Vec +where + T: IntoVal + TryFromVal, +{ + type Item = T; + type IntoIter = UnwrappedIter, T, T::Error>; + + fn into_iter(self) -> Self::IntoIter { + self.clone().into_iter() + } +} + +impl Extend for Vec +where + T: IntoVal + TryFromVal, +{ + fn extend>(&mut self, iter: I) { + for item in iter { + self.push_back(item); + } + } +} + +impl Vec +where + T: IntoVal + TryFromVal, +{ + /// Returns an iterator over the elements of the vec. + /// + /// Each element is converted from [Val] to `T` as it is yielded. + /// + /// ### Panics + /// + /// If any element cannot be converted to type `T`. Use + /// [`try_iter`](Vec::try_iter) to handle conversion errors. + #[inline(always)] + pub fn iter(&self) -> UnwrappedIter, T, T::Error> + where + T: IntoVal + TryFromVal + Clone, + T::Error: Debug, + { + self.try_iter().unwrapped() + } + + /// Returns an iterator over the elements of the vec, yielding + /// `Result` for each element. + #[inline(always)] + pub fn try_iter(&self) -> VecTryIter + where + T: IntoVal + TryFromVal + Clone, + { + VecTryIter::new(self.clone()) + } + + #[inline(always)] + pub fn into_try_iter(self) -> VecTryIter + where + T: IntoVal + TryFromVal + Clone, + T::Error: Debug, + { + VecTryIter::new(self) + } +} + +#[derive(Clone)] +pub struct VecTryIter { + vec: Vec, + start: u32, // inclusive + end: u32, // exclusive +} + +impl VecTryIter { + fn new(vec: Vec) -> Self { + Self { + start: 0, + end: vec.len(), + vec, + } + } + + fn into_vec(self) -> Vec { + self.vec.slice(self.start..self.end) + } +} + +impl Iterator for VecTryIter +where + T: IntoVal + TryFromVal, +{ + type Item = Result; + + fn next(&mut self) -> Option { + if self.start < self.end { + let val = self.vec.try_get_unchecked(self.start); + self.start += 1; + Some(val) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = (self.end - self.start) as usize; + (len, Some(len)) + } + + // TODO: Implement other functions as optimizations since the iterator is + // backed by an indexable collection. +} + +impl DoubleEndedIterator for VecTryIter +where + T: IntoVal + TryFromVal, +{ + fn next_back(&mut self) -> Option { + if self.start < self.end { + let val = self.vec.try_get_unchecked(self.end - 1); + self.end -= 1; + Some(val) + } else { + None + } + } + + // TODO: Implement other functions as optimizations since the iterator is + // backed by an indexable collection. +} + +impl FusedIterator for VecTryIter where T: IntoVal + TryFromVal {} + +impl ExactSizeIterator for VecTryIter +where + T: IntoVal + TryFromVal, +{ + fn len(&self) -> usize { + (self.end - self.start) as usize + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_vec_macro() { + let env = Env::default(); + assert_eq!(vec![&env], Vec::::new(&env)); + assert_eq!(vec![&env,], Vec::::new(&env)); + assert_eq!(vec![&env, 1], { + let mut v = Vec::new(&env); + v.push_back(1); + v + }); + assert_eq!(vec![&env, 1,], { + let mut v = Vec::new(&env); + v.push_back(1); + v + }); + assert_eq!(vec![&env, 3, 2, 1,], { + let mut v = Vec::new(&env); + v.push_back(3); + v.push_back(2); + v.push_back(1); + v + }); + } + + #[test] + fn test_vec_to_val() { + let env = Env::default(); + + let vec = Vec::::from_slice(&env, &[0, 1, 2, 3]); + let val: Val = vec.clone().into_val(&env); + let rt: Vec = val.into_val(&env); + + assert_eq!(vec, rt); + } + + #[test] + fn test_ref_vec_to_val() { + let env = Env::default(); + + let vec = Vec::::from_slice(&env, &[0, 1, 2, 3]); + let val: Val = (&vec).into_val(&env); + let rt: Vec = val.into_val(&env); + + assert_eq!(vec, rt); + } + + #[test] + fn test_double_ref_vec_to_val() { + let env = Env::default(); + + let vec = Vec::::from_slice(&env, &[0, 1, 2, 3]); + let val: Val = (&&vec).into_val(&env); + let rt: Vec = val.into_val(&env); + + assert_eq!(vec, rt); + } + + #[test] + fn test_vec_raw_val_type() { + let env = Env::default(); + + let mut vec = Vec::::new(&env); + assert_eq!(vec.len(), 0); + vec.push_back(10); + assert_eq!(vec.len(), 1); + vec.push_back(20); + assert_eq!(vec.len(), 2); + vec.push_back(30); + assert_eq!(vec.len(), 3); + + let vec_ref = &vec; + assert_eq!(vec_ref.len(), 3); + + let mut vec_copy = vec.clone(); + assert!(vec == vec_copy); + assert_eq!(vec_copy.len(), 3); + vec_copy.push_back(40); + assert_eq!(vec_copy.len(), 4); + assert!(vec != vec_copy); + + assert_eq!(vec.len(), 3); + assert_eq!(vec_ref.len(), 3); + + _ = vec_copy.pop_back_unchecked(); + assert!(vec == vec_copy); + } + + #[test] + fn test_vec_env_val_type() { + let env = Env::default(); + + let mut vec = Vec::::new(&env); + assert_eq!(vec.len(), 0); + vec.push_back(-10); + assert_eq!(vec.len(), 1); + vec.push_back(20); + assert_eq!(vec.len(), 2); + vec.push_back(-30); + assert_eq!(vec.len(), 3); + + let vec_ref = &vec; + assert_eq!(vec_ref.len(), 3); + + let mut vec_copy = vec.clone(); + assert!(vec == vec_copy); + assert_eq!(vec_copy.len(), 3); + vec_copy.push_back(40); + assert_eq!(vec_copy.len(), 4); + assert!(vec != vec_copy); + + assert_eq!(vec.len(), 3); + assert_eq!(vec_ref.len(), 3); + + _ = vec_copy.pop_back_unchecked(); + assert!(vec == vec_copy); + } + + #[test] + fn test_vec_to_vals() { + let env = Env::default(); + let vec = vec![&env, 0, 1, 2, 3, 4]; + let vals = vec.to_vals(); + assert_eq!( + vals, + vec![ + &env, + Val::from_i32(0).to_val(), + Val::from_i32(1).to_val(), + Val::from_i32(2).to_val(), + Val::from_i32(3).to_val(), + Val::from_i32(4).to_val(), + ] + ); + } + + #[test] + fn test_vec_recursive() { + let env = Env::default(); + + let mut vec_inner = Vec::::new(&env); + vec_inner.push_back(-10); + assert_eq!(vec_inner.len(), 1); + + let mut vec_outer = Vec::>::new(&env); + vec_outer.push_back(vec_inner); + assert_eq!(vec_outer.len(), 1); + } + + #[test] + fn test_vec_concat() { + let env = Env::default(); + let vec_1: Vec = vec![&env, 1, 2, 3]; + let vec_2: Vec = vec![&env, 4, 5, 6]; + let vec = vec![&env, vec_1, vec_2].concat(); + assert_eq!(vec, vec![&env, 1, 2, 3, 4, 5, 6]); + } + + #[test] + fn test_vec_slice() { + let env = Env::default(); + + let vec = vec![&env, 0, 1, 2, 3, 4]; + assert_eq!(vec.len(), 5); + + let slice = vec.slice(..); + assert_eq!(slice, vec![&env, 0, 1, 2, 3, 4]); + + let slice = vec.slice(0..5); + assert_eq!(slice, vec![&env, 0, 1, 2, 3, 4]); + + let slice = vec.slice(0..=4); + assert_eq!(slice, vec![&env, 0, 1, 2, 3, 4]); + + let slice = vec.slice(1..); + assert_eq!(slice, vec![&env, 1, 2, 3, 4]); + + let slice = vec.slice(..4); + assert_eq!(slice, vec![&env, 0, 1, 2, 3]); + + let slice = vec.slice(..=3); + assert_eq!(slice, vec![&env, 0, 1, 2, 3]); + + let slice = vec.slice(1..4); + assert_eq!(slice, vec![&env, 1, 2, 3]); + + let slice = vec.slice(1..=3); + assert_eq!(slice, vec![&env, 1, 2, 3]); + + // An exclusive start is technically possible due to the lack of + // constraints in the RangeBounds trait, however this is unlikely to + // happen since no syntax shorthand exists for it. + let slice = vec.slice((Bound::Excluded(0), Bound::Included(3))); + assert_eq!(slice, vec![&env, 1, 2, 3]); + let slice = vec.slice((Bound::Excluded(0), Bound::Excluded(3))); + assert_eq!(slice, vec![&env, 1, 2]); + } + + #[test] + fn test_vec_iter() { + let env = Env::default(); + + let vec: Vec<()> = vec![&env]; + let mut iter = vec.iter(); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let vec = vec![&env, 0, 1, 2, 3, 4]; + + let mut iter = vec.iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut iter = vec.iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next_back(), Some(4)); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next_back(), Some(3)); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + + let mut iter = vec.iter().rev(); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next_back(), Some(0)); + assert_eq!(iter.next_back(), Some(1)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_vec_iter_panic_on_conversion() { + let env = Env::default(); + + let vec: Val = (1i32,).try_into_val(&env).unwrap(); + let vec: Vec = vec.try_into_val(&env).unwrap(); + + let mut iter = vec.iter(); + iter.next(); + } + + #[test] + fn test_vec_try_iter() { + let env = Env::default(); + + let vec: Vec<()> = vec![&env]; + let mut iter = vec.try_iter(); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let vec = vec![&env, 0, 1, 2, 3, 4]; + + let mut iter = vec.try_iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(Ok(0))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next(), Some(Ok(1))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next(), Some(Ok(2))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(Ok(3))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(Ok(4))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + let mut iter = vec.try_iter(); + assert_eq!(iter.len(), 5); + assert_eq!(iter.next(), Some(Ok(0))); + assert_eq!(iter.len(), 4); + assert_eq!(iter.next_back(), Some(Ok(4))); + assert_eq!(iter.len(), 3); + assert_eq!(iter.next_back(), Some(Ok(3))); + assert_eq!(iter.len(), 2); + assert_eq!(iter.next(), Some(Ok(1))); + assert_eq!(iter.len(), 1); + assert_eq!(iter.next(), Some(Ok(2))); + assert_eq!(iter.len(), 0); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + + let mut iter = vec.try_iter().rev(); + assert_eq!(iter.next(), Some(Ok(4))); + assert_eq!(iter.next_back(), Some(Ok(0))); + assert_eq!(iter.next_back(), Some(Ok(1))); + assert_eq!(iter.next(), Some(Ok(3))); + assert_eq!(iter.next(), Some(Ok(2))); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(iter.next_back(), None); + } + + #[test] + fn test_vec_try_iter_error_on_conversion() { + let env = Env::default(); + + let vec: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let vec: Vec = vec.try_into_val(&env).unwrap(); + + let mut iter = vec.try_iter(); + assert_eq!(iter.next(), Some(Ok(1))); + assert_eq!(iter.next(), Some(Err(ConversionError.into()))); + } + + #[test] + fn test_vec_iter_into_vec() { + let env = Env::default(); + + let vec = vec![&env, 0, 1, 2, 3, 4]; + + let mut iter = vec.try_iter(); + assert_eq!(iter.next(), Some(Ok(0))); + assert_eq!(iter.next(), Some(Ok(1))); + assert_eq!(iter.into_vec(), vec![&env, 2, 3, 4]); + } + + #[test] + fn test_contains() { + let env = Env::default(); + let vec = vec![&env, 0, 3, 5, 7, 9, 5]; + assert_eq!(vec.contains(&2), false); + assert_eq!(vec.contains(2), false); + assert_eq!(vec.contains(&3), true); + assert_eq!(vec.contains(3), true); + assert_eq!(vec.contains(&5), true); + assert_eq!(vec.contains(5), true); + } + + #[test] + fn test_first_index_of() { + let env = Env::default(); + + let vec = vec![&env, 0, 3, 5, 7, 9, 5]; + assert_eq!(vec.first_index_of(&2), None); + assert_eq!(vec.first_index_of(2), None); + assert_eq!(vec.first_index_of(&3), Some(1)); + assert_eq!(vec.first_index_of(3), Some(1)); + assert_eq!(vec.first_index_of(&5), Some(2)); + assert_eq!(vec.first_index_of(5), Some(2)); + } + + #[test] + fn test_last_index_of() { + let env = Env::default(); + + let vec = vec![&env, 0, 3, 5, 7, 9, 5]; + assert_eq!(vec.last_index_of(&2), None); + assert_eq!(vec.last_index_of(2), None); + assert_eq!(vec.last_index_of(&3), Some(1)); + assert_eq!(vec.last_index_of(3), Some(1)); + assert_eq!(vec.last_index_of(&5), Some(5)); + assert_eq!(vec.last_index_of(5), Some(5)); + } + + #[test] + fn test_binary_search() { + let env = Env::default(); + + let vec = vec![&env, 0, 3, 5, 5, 7, 9]; + assert_eq!(vec.binary_search(&2), Err(1)); + assert_eq!(vec.binary_search(2), Err(1)); + assert_eq!(vec.binary_search(&3), Ok(1)); + assert_eq!(vec.binary_search(3), Ok(1)); + assert_eq!(vec.binary_search(&5), Ok(3)); + assert_eq!(vec.binary_search(5), Ok(3)); + } + + #[cfg(not(target_family = "wasm"))] + #[test] + fn test_scval_accessibility_from_udt_types() { + use crate::TryFromVal; + let env = Env::default(); + let v = vec![&env, 1]; + let val: ScVal = v.clone().try_into().unwrap(); + let roundtrip = Vec::::try_from_val(&env, &val).unwrap(); + assert_eq!(v, roundtrip); + } + + #[test] + fn test_insert_and_set() { + let env = Env::default(); + let mut v = Vec::::new(&env); + v.insert(0, 3); + v.insert(0, 1); + v.insert(1, 4); + v.insert(3, 6); + assert_eq!(v, vec![&env, 1, 4, 3, 6]); + v.set(0, 7); + v.set(1, 6); + v.set(2, 2); + v.set(3, 5); + assert_eq!(v, vec![&env, 7, 6, 2, 5]); + } + + #[test] + fn test_is_empty_and_len() { + let env = Env::default(); + + let mut v: Vec = vec![&env, 1, 4, 3]; + assert_eq!(v.is_empty(), false); + assert_eq!(v.len(), 3); + + v = vec![&env]; + assert_eq!(v.is_empty(), true); + assert_eq!(v.len(), 0); + } + + #[test] + fn test_push_pop_front() { + let env = Env::default(); + + let mut v = Vec::::new(&env); + v.push_front(42); + assert_eq!(v, vec![&env, 42]); + v.push_front(1); + assert_eq!(v, vec![&env, 1, 42]); + v.push_front(5); + assert_eq!(v, vec![&env, 5, 1, 42]); + v.push_front(7); + assert_eq!(v, vec![&env, 7, 5, 1, 42]); + + let popped = v.pop_front(); + assert_eq!(popped, Some(7)); + assert_eq!(v, vec![&env, 5, 1, 42]); + + let popped = v.try_pop_front(); + assert_eq!(popped, Ok(Some(5))); + assert_eq!(v, vec![&env, 1, 42]); + + let popped = v.pop_front_unchecked(); + assert_eq!(popped, 1); + assert_eq!(v, vec![&env, 42]); + + let popped = v.try_pop_front_unchecked(); + assert_eq!(popped, Ok(42)); + assert_eq!(v, vec![&env]); + + assert_eq!(v.pop_front(), None); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_pop_front_panics_on_conversion() { + let env = Env::default(); + + let v: Val = (1i32,).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + v.pop_front(); + } + + #[test] + fn test_try_pop_front_errors_on_conversion() { + let env = Env::default(); + + let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + assert_eq!(v.try_pop_front(), Ok(Some(1))); + assert_eq!(v.try_pop_front(), Err(ConversionError.into())); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_pop_front_unchecked_panics_on_conversion() { + let env = Env::default(); + + let v: Val = (1i32,).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + v.pop_front_unchecked(); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_pop_front_unchecked_panics_on_out_of_bounds() { + let env = Env::default(); + + let mut v = Vec::::new(&env); + + v.pop_front_unchecked(); + } + + #[test] + fn test_try_pop_front_unchecked_errors_on_conversion() { + let env = Env::default(); + + let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + assert_eq!(v.try_pop_front_unchecked(), Ok(1)); + assert_eq!(v.try_pop_front_unchecked(), Err(ConversionError.into())); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_try_pop_front_unchecked_panics_on_out_of_bounds() { + let env = Env::default(); + + let mut v = Vec::::new(&env); + + let _ = v.try_pop_front_unchecked(); + } + + #[test] + fn test_push_pop_back() { + let env = Env::default(); + + let mut v = Vec::::new(&env); + v.push_back(42); + assert_eq!(v, vec![&env, 42]); + v.push_back(1); + assert_eq!(v, vec![&env, 42, 1]); + v.push_back(5); + assert_eq!(v, vec![&env, 42, 1, 5]); + v.push_back(7); + assert_eq!(v, vec![&env, 42, 1, 5, 7]); + + let popped = v.pop_back(); + assert_eq!(popped, Some(7)); + assert_eq!(v, vec![&env, 42, 1, 5]); + + let popped = v.try_pop_back(); + assert_eq!(popped, Ok(Some(5))); + assert_eq!(v, vec![&env, 42, 1]); + + let popped = v.pop_back_unchecked(); + assert_eq!(popped, 1); + assert_eq!(v, vec![&env, 42]); + + let popped = v.try_pop_back_unchecked(); + assert_eq!(popped, Ok(42)); + assert_eq!(v, vec![&env]); + + assert_eq!(v.pop_back(), None); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_pop_back_panics_on_conversion() { + let env = Env::default(); + + let v: Val = (1i32,).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + v.pop_back(); + } + + #[test] + fn test_try_pop_back_errors_on_conversion() { + let env = Env::default(); + + let v: Val = (1i32, 2i64).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + assert_eq!(v.try_pop_back(), Ok(Some(2))); + assert_eq!(v.try_pop_back(), Err(ConversionError.into())); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_pop_back_unchecked_panics_on_conversion() { + let env = Env::default(); + + let v: Val = (1i32,).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + v.pop_back_unchecked(); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_pop_back_unchecked_panics_on_out_of_bounds() { + let env = Env::default(); + + let mut v = Vec::::new(&env); + + v.pop_back_unchecked(); + } + + #[test] + fn test_try_pop_back_unchecked_errors_on_conversion() { + let env = Env::default(); + + let v: Val = (1i32, 2i64).try_into_val(&env).unwrap(); + let mut v: Vec = v.try_into_val(&env).unwrap(); + + assert_eq!(v.try_pop_back_unchecked(), Ok(2)); + assert_eq!(v.try_pop_back_unchecked(), Err(ConversionError.into())); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_try_pop_back_unchecked_panics_on_out_of_bounds() { + let env = Env::default(); + + let mut v = Vec::::new(&env); + + let _ = v.try_pop_back_unchecked(); + } + + #[test] + fn test_get() { + let env = Env::default(); + + let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + + // get each item + assert_eq!(v.get(3), Some(5)); + assert_eq!(v.get(0), Some(0)); + assert_eq!(v.get(1), Some(3)); + assert_eq!(v.get(2), Some(5)); + assert_eq!(v.get(5), Some(9)); + assert_eq!(v.get(4), Some(7)); + + assert_eq!(v.get(v.len()), None); + assert_eq!(v.get(v.len() + 1), None); + assert_eq!(v.get(u32::MAX), None); + + // tests on an empty vec + let v = Vec::::new(&env); + assert_eq!(v.get(0), None); + assert_eq!(v.get(v.len()), None); + assert_eq!(v.get(v.len() + 1), None); + assert_eq!(v.get(u32::MAX), None); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_get_panics_on_conversion() { + let env = Env::default(); + + let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let v: Vec = v.try_into_val(&env).unwrap(); + + // panic because element one is not of the expected type + assert_eq!(v.get(1), Some(5)); + } + + #[test] + fn test_try_get() { + let env = Env::default(); + + let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + + // get each item + assert_eq!(v.try_get(3), Ok(Some(5))); + assert_eq!(v.try_get(0), Ok(Some(0))); + assert_eq!(v.try_get(1), Ok(Some(3))); + assert_eq!(v.try_get(2), Ok(Some(5))); + assert_eq!(v.try_get(5), Ok(Some(9))); + assert_eq!(v.try_get(4), Ok(Some(7))); + + assert_eq!(v.try_get(v.len()), Ok(None)); + assert_eq!(v.try_get(v.len() + 1), Ok(None)); + assert_eq!(v.try_get(u32::MAX), Ok(None)); + + // tests on an empty vec + let v = Vec::::new(&env); + assert_eq!(v.try_get(0), Ok(None)); + assert_eq!(v.try_get(v.len()), Ok(None)); + assert_eq!(v.try_get(v.len() + 1), Ok(None)); + assert_eq!(v.try_get(u32::MAX), Ok(None)); + + // errors + let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let v: Vec = v.try_into_val(&env).unwrap(); + assert_eq!(v.try_get(0), Ok(Some(1))); + assert_eq!(v.try_get(1), Err(ConversionError.into())); + } + + #[test] + fn test_get_unchecked() { + let env = Env::default(); + + let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + + // get each item + assert_eq!(v.get_unchecked(3), 5); + assert_eq!(v.get_unchecked(0), 0); + assert_eq!(v.get_unchecked(1), 3); + assert_eq!(v.get_unchecked(2), 5); + assert_eq!(v.get_unchecked(5), 9); + assert_eq!(v.get_unchecked(4), 7); + } + + #[test] + #[should_panic(expected = "Error(Value, UnexpectedType)")] + fn test_get_unchecked_panics_on_conversion() { + let env = Env::default(); + + let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let v: Vec = v.try_into_val(&env).unwrap(); + + // panic because element one is not of the expected type + v.get_unchecked(1); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_get_unchecked_panics_on_out_of_bounds() { + let env = Env::default(); + + let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + _ = v.get_unchecked(v.len()); // out of bound get + } + + #[test] + fn test_try_get_unchecked() { + let env = Env::default(); + + let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + + // get each item + assert_eq!(v.try_get_unchecked(3), Ok(5)); + assert_eq!(v.try_get_unchecked(0), Ok(0)); + assert_eq!(v.try_get_unchecked(1), Ok(3)); + assert_eq!(v.try_get_unchecked(2), Ok(5)); + assert_eq!(v.try_get_unchecked(5), Ok(9)); + assert_eq!(v.try_get_unchecked(4), Ok(7)); + + // errors + let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); + let v: Vec = v.try_into_val(&env).unwrap(); + assert_eq!(v.try_get_unchecked(0), Ok(1)); + assert_eq!(v.try_get_unchecked(1), Err(ConversionError.into())); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_try_get_unchecked_panics() { + let env = Env::default(); + + let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + _ = v.try_get_unchecked(v.len()); // out of bound get + } + + #[test] + fn test_remove() { + let env = Env::default(); + let mut v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + + assert_eq!(v.remove(0), Some(())); + assert_eq!(v.remove(2), Some(())); + assert_eq!(v.remove(3), Some(())); + + assert_eq!(v, vec![&env, 3, 5, 7]); + assert_eq!(v.len(), 3); + + // out of bound removes + assert_eq!(v.remove(v.len()), None); + assert_eq!(v.remove(v.len() + 1), None); + assert_eq!(v.remove(u32::MAX), None); + + // remove rest of items + assert_eq!(v.remove(0), Some(())); + assert_eq!(v.remove(0), Some(())); + assert_eq!(v.remove(0), Some(())); + assert_eq!(v, vec![&env]); + assert_eq!(v.len(), 0); + + // try remove from empty vec + assert_eq!(v.remove(0), None); + assert_eq!(v.remove(v.len()), None); + assert_eq!(v.remove(v.len() + 1), None); + assert_eq!(v.remove(u32::MAX), None); + } + + #[test] + fn test_remove_unchecked() { + let env = Env::default(); + let mut v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + + assert_eq!(v.remove_unchecked(0), ()); + assert_eq!(v.remove_unchecked(2), ()); + assert_eq!(v.remove_unchecked(3), ()); + + assert_eq!(v, vec![&env, 3, 5, 7]); + assert_eq!(v.len(), 3); + + // remove rest of items + assert_eq!(v.remove_unchecked(0), ()); + assert_eq!(v.remove_unchecked(0), ()); + assert_eq!(v.remove_unchecked(0), ()); + assert_eq!(v, vec![&env]); + assert_eq!(v.len(), 0); + } + + #[test] + #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] + fn test_remove_unchecked_panics() { + let env = Env::default(); + let mut v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; + v.remove_unchecked(v.len()) + } + + #[test] + fn test_extend() { + let env = Env::default(); + let mut v: Vec = vec![&env, 1, 2, 3]; + + // Extend with a std vector + let items = std::vec![4, 5, 6]; + v.extend(items); + assert_eq!(v, vec![&env, 1, 2, 3, 4, 5, 6]); + assert_eq!(v.len(), 6); + + // Extend with an array + v.extend([7, 8, 9]); + assert_eq!(v, vec![&env, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + assert_eq!(v.len(), 9); + + // Extend with an empty iterator + let empty: std::vec::Vec = std::vec::Vec::new(); + v.extend(empty); + assert_eq!(v, vec![&env, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + assert_eq!(v.len(), 9); + } + + #[test] + fn test_extend_empty_vec() { + let env = Env::default(); + let mut v: Vec = vec![&env]; + + // Extend empty vec with items + v.extend([1, 2, 3, 4, 5]); + assert_eq!(v, vec![&env, 1, 2, 3, 4, 5]); + assert_eq!(v.len(), 5); + } + + #[test] + fn test_from_iter() { + let env = Env::default(); + + // Create from std vector iterator + let items = std::vec![1, 2, 3, 4, 5]; + let v = Vec::from_iter(&env, items); + assert_eq!(v, vec![&env, 1, 2, 3, 4, 5]); + assert_eq!(v.len(), 5); + + // Create from array iterator + let v2 = Vec::from_iter(&env, [10, 20, 30]); + assert_eq!(v2, vec![&env, 10, 20, 30]); + assert_eq!(v2.len(), 3); + + // Create from range + let v3 = Vec::from_iter(&env, 1..=4); + assert_eq!(v3, vec![&env, 1, 2, 3, 4]); + assert_eq!(v3.len(), 4); + } + + #[test] + fn test_from_iter_empty() { + let env = Env::default(); + + // Create from empty iterator + let empty: std::vec::Vec = std::vec::Vec::new(); + let v = Vec::from_iter(&env, empty); + assert_eq!(v, vec![&env]); + assert_eq!(v.len(), 0); + + // Create from empty range + let v2 = Vec::from_iter(&env, 1..1); + assert_eq!(v2, vec![&env]); + assert_eq!(v2.len(), 0); + } + + #[test] + fn test_from_iter_different_types() { + let env = Env::default(); + + // Test with strings + let strings = std::vec!["hello".to_string(), "world".to_string(), "test".to_string()]; + let v = Vec::from_iter(&env, strings); + assert_eq!( + v, + vec![ + &env, + "hello".to_string(), + "world".to_string(), + "test".to_string() + ] + ); + assert_eq!(v.len(), 3); + + // Test with booleans + let bools = [true, false, true, false]; + let v2 = Vec::from_iter(&env, bools.into_iter()); + assert_eq!(v2, vec![&env, true, false, true, false]); + assert_eq!(v2.len(), 4); + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/xdr.rs b/temp_sdk/soroban-sdk-26.0.1/src/xdr.rs new file mode 100644 index 0000000..5458815 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/src/xdr.rs @@ -0,0 +1,118 @@ +//! Convert values to and from [Bytes]. +//! +//! All types that are convertible to and from [Val] implement the +//! [ToXdr] and [FromXdr] traits, and serialize to the ScVal XDR form. +//! +//! ### Examples +//! +//! ``` +//! use soroban_sdk::{ +//! xdr::{FromXdr, ToXdr}, +//! Env, Bytes, IntoVal, TryFromVal, +//! }; +//! +//! let env = Env::default(); +//! +//! let value: u32 = 5; +//! +//! let bytes = value.to_xdr(&env); +//! assert_eq!(bytes.len(), 8); +//! +//! let roundtrip = u32::from_xdr(&env, &bytes); +//! assert_eq!(roundtrip, Ok(value)); +//! ``` + +use crate::{ + env::internal::Env as _, unwrap::UnwrapInfallible, Bytes, Env, IntoVal, TryFromVal, Val, +}; + +// Re-export all the XDR from the environment. +pub use crate::env::xdr::*; + +/// Implemented by types that can be serialized to [Bytes] as XDR. +/// +/// All types that are convertible to [Val] implement this trait. The value is +/// first converted to a [Val], then serialized to XDR in its [ScVal] form. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{xdr::ToXdr, Env}; +/// +/// let env = Env::default(); +/// +/// let value: u32 = 5; +/// let bytes = value.to_xdr(&env); +/// assert_eq!(bytes.len(), 8); +/// ``` +pub trait ToXdr { + /// Serializes the value to XDR as [Bytes]. + fn to_xdr(self, env: &Env) -> Bytes; +} + +/// Implemented by types that can be deserialized from [Bytes] containing XDR. +/// +/// All types that are convertible from [Val] implement this trait. The bytes +/// are deserialized from their [ScVal] XDR form into a [Val], then converted +/// to the target type. +/// +/// ### Errors +/// +/// Returns an error if the [Val] cannot be converted into the target type. +/// +/// ### Panics +/// +/// Panics if the provided bytes are not valid XDR for an [ScVal]. +/// +/// ### Examples +/// +/// ``` +/// use soroban_sdk::{xdr::{ToXdr, FromXdr}, Env}; +/// +/// let env = Env::default(); +/// +/// let value: u32 = 5; +/// let bytes = value.to_xdr(&env); +/// +/// let roundtrip = u32::from_xdr(&env, &bytes); +/// assert_eq!(roundtrip, Ok(5)); +/// ``` +pub trait FromXdr: Sized { + /// The error type returned if the [Val] cannot be converted into the + /// target type. + type Error; + /// Deserializes the value from XDR [Bytes]. + /// + /// ### Errors + /// + /// Returns an error if the [Val] cannot be converted into the target + /// type. + /// + /// ### Panics + /// + /// Panics if the provided bytes are not valid XDR for an [ScVal]. + fn from_xdr(env: &Env, b: &Bytes) -> Result; +} + +impl ToXdr for T +where + T: IntoVal, +{ + fn to_xdr(self, env: &Env) -> Bytes { + let val: Val = self.into_val(env); + let bin = env.serialize_to_bytes(val).unwrap_infallible(); + unsafe { Bytes::unchecked_new(env.clone(), bin) } + } +} + +impl FromXdr for T +where + T: TryFromVal, +{ + type Error = T::Error; + + fn from_xdr(env: &Env, b: &Bytes) -> Result { + let t = env.deserialize_from_bytes(b.into()).unwrap_infallible(); + T::try_from_val(env, &t) + } +} diff --git a/temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md b/temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md new file mode 100644 index 0000000..0e8b3a0 --- /dev/null +++ b/temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md @@ -0,0 +1,6 @@ +# test_wasms + +Files contained in this directory are used in a few SDK tests that are sensitive +to Wasm content changes. + +`test_contract_data.wasm` is a build of `tests/contract_data` test contract. From d82eaa312c92fb83ebae50fd1e93b1c95630948b Mon Sep 17 00:00:00 2001 From: Qoder-Undefined Date: Thu, 23 Jul 2026 16:38:14 +0100 Subject: [PATCH 2/4] removed unwanted files --- .../doctest_fixtures/README.md | 8 - .../src/testutils/arbitrary.rs | 2235 ----------------- .../src/testutils/cost_estimate.rs | 153 -- .../src/testutils/mock_auth.rs | 145 -- .../soroban-sdk-26.0.1/src/testutils/sign.rs | 97 - .../src/testutils/storage.rs | 41 - .../soroban-sdk-26.0.1/test_wasms/README.md | 6 - 7 files changed, 2685 deletions(-) delete mode 100644 temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md diff --git a/temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md b/temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md deleted file mode 100644 index 61ea2ef..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/doctest_fixtures/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# doctest_fixtures - -Files contained in this directory are used within examples inside docs, i.e. -doctests. - -`contract.wasm` is a copy of `test_add_u64` test contract. - -`contract_with_constructor.wasm` is a copy of `test_constructor` test contract. diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs deleted file mode 100644 index ea8c695..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/testutils/arbitrary.rs +++ /dev/null @@ -1,2235 +0,0 @@ -//! Support for fuzzing Soroban contracts with [`cargo-fuzz`]. -//! -//! This module provides a pattern for generating Soroban contract types for the -//! purpose of fuzzing Soroban contracts. It is focused on implementing the -//! [`Arbitrary`] trait that `cargo-fuzz` relies on to feed fuzzers with -//! generated Rust values. -//! -//! [`cargo-fuzz`]: https://github.com/rust-fuzz/cargo-fuzz/ -//! [`Arbitrary`]: ::arbitrary::Arbitrary -//! -//! This module -//! -//! - defines the [`SorobanArbitrary`] trait, -//! - reexports the [`arbitrary`] crate and the [`Arbitrary`] type. -//! -//! This module is only available when the "testutils" Cargo feature is defined. -//! -//! -//! ## About `cargo-fuzz` and `Arbitrary` -//! -//! In its basic operation `cargo-fuzz` fuzz generates raw bytes and feeds them -//! to a program-dependent fuzzer designed to exercise a program, in our case a -//! Soroban contract. -//! -//! `cargo-fuzz` programs declare their entry points with a macro: -//! -//! ``` -//! # macro_rules! fuzz_target { -//! # (|$data:ident: $dty: ty| $body:block) => { }; -//! # } -//! fuzz_target!(|input: &[u8]| { -//! // feed bytes to the program -//! }); -//! ``` -//! -//! More sophisticated fuzzers accept not bytes but Rust types: -//! -//! ``` -//! # use arbitrary::Arbitrary; -//! # macro_rules! fuzz_target { -//! # (|$data:ident: $dty: ty| $body:block) => { }; -//! # } -//! #[derive(Arbitrary, Debug)] -//! struct FuzzDeposit { -//! deposit_amount: i128, -//! } -//! -//! fuzz_target!(|input: FuzzDeposit| { -//! // fuzz the program based on the input -//! }); -//! ``` -//! -//! Types accepted as input to `fuzz_target` must implement the `Arbitrary` trait, -//! which transforms bytes to Rust types. -//! -//! -//! ## The `SorobanArbitrary` trait -//! -//! Soroban types are managed by the host environment, and so must be created -//! from an [`Env`] value; `Arbitrary` values though must be created from -//! nothing but bytes. The [`SorobanArbitrary`] trait, implemented for all -//! Soroban contract types, exists to bridge this gap: it defines a _prototype_ -//! pattern whereby the `fuzz_target` macro creates prototype values that the -//! fuzz program can convert to contract values with the standard soroban -//! conversion traits, [`FromVal`] or [`IntoVal`]. -//! -//! [`Env`]: crate::Env -//! [`FromVal`]: crate::FromVal -//! [`IntoVal`]: crate::IntoVal -//! -//! The types of prototypes are identified by the associated type, -//! [`SorobanArbitrary::Prototype`]: -//! -//! ``` -//! # use soroban_sdk::testutils::arbitrary::Arbitrary; -//! # use soroban_sdk::{TryFromVal, IntoVal, Val, Env}; -//! pub trait SorobanArbitrary: -//! TryFromVal + IntoVal + TryFromVal -//! { -//! type Prototype: for <'a> Arbitrary<'a>; -//! } -//! ``` -//! -//! Types that implement `SorobanArbitrary` include: -//! -//! - `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `I256`, `U256`, `()`, and `bool`, -//! - [`Error`], -//! - [`Bytes`], [`BytesN`], [`Vec`], [`Map`], -//! - [`Address`], [`Symbol`], -//! - [`Val`], -//! -//! [`I256`]: crate::I256 -//! [`U256`]: crate::U256 -//! [`Error`]: crate::Error -//! [`Bytes`]: crate::Bytes -//! [`BytesN`]: crate::BytesN -//! [`Vec`]: crate::Vec -//! [`Map`]: crate::Map -//! [`Address`]: crate::Address -//! [`Symbol`]: crate::Symbol -//! [`Val`]: crate::Val -//! -//! All user-defined contract types, those with the [`contracttype`] attribute, -//! automatically derive `SorobanArbitrary`. Note that `SorobanArbitrary` is -//! only derived when the "testutils" Cargo feature is active. This implies -//! that, in general, to make a Soroban contract fuzzable, the contract crate -//! must define a "testutils" Cargo feature, that feature should turn on the -//! "soroban-sdk/testutils" feature, and the fuzz test, which is its own crate, -//! must turn that feature on. -//! -//! [`contracttype`]: crate::contracttype -//! -//! -//! ## Example: take a Soroban `Vec` of `Address` as fuzzer input -//! -//! ``` -//! # macro_rules! fuzz_target { -//! # (|$data:ident: $dty: ty| $body:block) => { }; -//! # } -//! use soroban_sdk::{Address, Env, Vec}; -//! use soroban_sdk::testutils::arbitrary::SorobanArbitrary; -//! -//! fuzz_target!(|input: as SorobanArbitrary>::Prototype| { -//! let env = Env::default(); -//! let addresses: Vec
= input.into_val(&env); -//! // fuzz the program based on the input -//! }); -//! ``` -//! -//! -//! ## Example: take a custom contract type as fuzzer input -//! -//! ``` -//! # macro_rules! fuzz_target { -//! # (|$data:ident: $dty: ty| $body:block) => { }; -//! # } -//! use soroban_sdk::{Address, Env, Vec}; -//! use soroban_sdk::contracttype; -//! use soroban_sdk::testutils::arbitrary::{Arbitrary, SorobanArbitrary}; -//! use std::vec::Vec as RustVec; -//! -//! #[derive(Arbitrary, Debug)] -//! struct TestInput { -//! deposit_amount: i128, -//! claim_address:
::Prototype, -//! time_bound: ::Prototype, -//! } -//! -//! #[contracttype] -//! pub struct TimeBound { -//! pub kind: TimeBoundKind, -//! pub timestamp: u64, -//! } -//! -//! #[contracttype] -//! pub enum TimeBoundKind { -//! Before, -//! After, -//! } -//! -//! fuzz_target!(|input: TestInput| { -//! let env = Env::default(); -//! let claim_address: Address = input.claim_address.into_val(&env); -//! let time_bound: TimeBound = input.time_bound.into_val(&env); -//! // fuzz the program based on the input -//! }); -//! ``` - -/// A reexport of the `arbitrary` crate. -/// -/// Used by the `contracttype` macro to derive `Arbitrary`. -pub use arbitrary; - -// Used often enough in fuzz tests to want direct access to it. -pub use arbitrary::Arbitrary; - -// Used by `contracttype` -#[doc(hidden)] -pub use std; - -pub use api::*; -pub use fuzz_test_helpers::*; - -/// The traits that must be implemented on Soroban types to support fuzzing. -/// -/// These allow for ergonomic conversion from a randomly-generated "prototype" -/// that implements `Arbitrary` into `Env`-"hosted" values that are paired with an -/// `Env`. -/// -/// These traits are intended to be easy to automatically derive. -mod api { - use crate::Env; - use crate::Val; - use crate::{IntoVal, TryFromVal}; - use arbitrary::Arbitrary; - - /// An `Env`-hosted contract value that can be randomly generated. - /// - /// Types that implement `SorabanArbitrary` have an associated "prototype" - /// type that implements [`Arbitrary`]. - /// - /// This exists partly so that the prototype can be named like - /// - /// ``` - /// # macro_rules! fuzz_target { - /// # (|$data:ident: $dty: ty| $body:block) => { }; - /// # } - /// # use soroban_sdk::{Address, Env, Vec, Bytes}; - /// # use soroban_sdk::testutils::arbitrary::SorobanArbitrary; - /// fuzz_target!(|input: ::Prototype| { - /// // ... - /// }); - /// ``` - // This also makes derivation of `SorobanArbitrary` for custom types easier - // since we depend on all fields also implementing `SorobanArbitrary`. - // - // The IntoVal + TryFromVal bounds are to satisfy - // the bounds of Vec and Map, so that collections of prototypes can be - // converted to contract types. - pub trait SorobanArbitrary: - TryFromVal + IntoVal + TryFromVal - { - /// A type that implements [`Arbitrary`] and can be converted to this - /// [`SorobanArbitrary`] type. - // NB: The `Arbitrary` bound here is not necessary for the correct use of - // `SorobanArbitrary`, but it makes the purpose clear. - type Prototype: for<'a> Arbitrary<'a>; - } -} - -/// Implementations of `soroban_sdk::testutils::arbitrary::api` for Rust scalar types. -/// -/// These types -/// -/// - do not have a distinct `Arbitrary` prototype, -/// i.e. they use themselves as the `SorobanArbitrary::Prototype` type, -/// - implement `Arbitrary` in the `arbitrary` crate, -/// - trivially implement `TryFromVal`, -/// -/// Examples: -/// -/// - `u32` -mod scalars { - use super::api::*; - - impl SorobanArbitrary for () { - type Prototype = (); - } - - impl SorobanArbitrary for bool { - type Prototype = bool; - } - - impl SorobanArbitrary for u32 { - type Prototype = u32; - } - - impl SorobanArbitrary for i32 { - type Prototype = i32; - } - - impl SorobanArbitrary for u64 { - type Prototype = u64; - } - - impl SorobanArbitrary for i64 { - type Prototype = i64; - } - - impl SorobanArbitrary for u128 { - type Prototype = u128; - } - - impl SorobanArbitrary for i128 { - type Prototype = i128; - } -} - -/// Implementations of `soroban_sdk::testutils::arbitrary::api` for Soroban types that do not -/// need access to the Soroban host environment. -/// -/// These types -/// -/// - do not have a distinct `Arbitrary` prototype, -/// i.e. they use themselves as the `SorobanArbitrary::Prototype` type, -/// - implement `Arbitrary` in the `soroban-env-common` crate, -/// - trivially implement `TryFromVal`, -/// -/// Examples: -/// -/// - `Error` -mod simple { - use super::api::*; - pub use crate::Error; - - impl SorobanArbitrary for Error { - type Prototype = Error; - } -} - -/// Implementations of `soroban_sdk::testutils::arbitrary::api` for Soroban types that do -/// need access to the Soroban host environment. -/// -/// These types -/// -/// - have a distinct `Arbitrary` prototype that derives `Arbitrary`, -/// - require an `Env` to be converted to their actual contract type. -/// -/// Examples: -/// -/// - `Vec` -mod objects { - use arbitrary::{Arbitrary, Result as ArbitraryResult, Unstructured}; - - use super::api::*; - use super::composite::ArbitraryVal; - use crate::env::FromVal; - use crate::ConversionError; - use crate::{Env, IntoVal, TryFromVal, TryIntoVal}; - - use crate::crypto::bn254::{ - Bn254Fp, Bn254Fr, Bn254G1Affine, Bn254G2Affine, BN254_FP_SERIALIZED_SIZE, - BN254_G1_SERIALIZED_SIZE, BN254_G2_SERIALIZED_SIZE, - }; - use crate::xdr::{Int256Parts, ScVal, UInt256Parts}; - use crate::{ - crypto::bls12_381::{ - Bls12381Fp, Bls12381Fp2, Bls12381Fr, Bls12381G1Affine, Bls12381G2Affine, - FP2_SERIALIZED_SIZE, FP_SERIALIZED_SIZE, G1_SERIALIZED_SIZE, G2_SERIALIZED_SIZE, - }, - Address, Bytes, BytesN, Duration, Map, MuxedAddress, String, Symbol, Timepoint, Val, Vec, - I256, U256, - }; - - use std::string::String as RustString; - use std::vec::Vec as RustVec; - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryOption(Option); - - impl SorobanArbitrary for Option - where - T: SorobanArbitrary, - Val: TryFromVal, - { - type Prototype = ArbitraryOption; - } - - impl TryFromVal> for Option - where - T: SorobanArbitrary, - { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryOption) -> Result { - match v.0 { - Some(ref t) => Ok(Some(t.into_val(env))), - None => Ok(None), - } - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryU256 { - parts: (u64, u64, u64, u64), - } - - impl SorobanArbitrary for U256 { - type Prototype = ArbitraryU256; - } - - impl TryFromVal for U256 { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryU256) -> Result { - let v = ScVal::U256(UInt256Parts { - hi_hi: v.parts.0, - hi_lo: v.parts.1, - lo_hi: v.parts.2, - lo_lo: v.parts.3, - }); - let v = Val::try_from_val(env, &v)?; - v.try_into_val(env) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryI256 { - parts: (i64, u64, u64, u64), - } - - impl SorobanArbitrary for I256 { - type Prototype = ArbitraryI256; - } - - impl TryFromVal for I256 { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryI256) -> Result { - let v = ScVal::I256(Int256Parts { - hi_hi: v.parts.0, - hi_lo: v.parts.1, - lo_hi: v.parts.2, - lo_lo: v.parts.3, - }); - let v = Val::try_from_val(env, &v)?; - v.try_into_val(env) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBytes { - vec: RustVec, - } - - impl SorobanArbitrary for Bytes { - type Prototype = ArbitraryBytes; - } - - impl TryFromVal for Bytes { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryBytes) -> Result { - Self::try_from_val(env, &v.vec.as_slice()) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryString { - inner: RustString, - } - - impl SorobanArbitrary for String { - type Prototype = ArbitraryString; - } - - impl TryFromVal for String { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryString) -> Result { - Self::try_from_val(env, &v.inner.as_str()) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBytesN { - array: [u8; N], - } - - impl SorobanArbitrary for BytesN { - type Prototype = ArbitraryBytesN; - } - - impl TryFromVal> for BytesN { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryBytesN) -> Result { - Self::try_from_val(env, &v.array) - } - } - - ////////////////////////////////// - - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitrarySymbol { - s: RustString, - } - - impl<'a> Arbitrary<'a> for ArbitrarySymbol { - fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult { - let valid_chars = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - let valid_chars = valid_chars.as_bytes(); - let mut chars = vec![]; - let len = u.int_in_range(0..=32)?; - for _ in 0..len { - let ch = u.choose(valid_chars)?; - chars.push(*ch); - } - Ok(ArbitrarySymbol { - s: RustString::from_utf8(chars).expect("utf8"), - }) - } - } - - impl SorobanArbitrary for Symbol { - type Prototype = ArbitrarySymbol; - } - - impl TryFromVal for Symbol { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitrarySymbol) -> Result { - Self::try_from_val(env, &v.s.as_str()) - } - } - - ////////////////////////////////// - - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryVec { - Good(RustVec), - // Vec can be constructed with non-T values. - Wrong(RustVec), - } - - impl<'a, T> Arbitrary<'a> for ArbitraryVec - where - T: Arbitrary<'a>, - { - fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult> { - // How frequently we provide ArbitraryVec::Wrong - const WRONG_TYPE_RATIO: (u16, u16) = (1, 1000); - - if u.ratio(WRONG_TYPE_RATIO.0, WRONG_TYPE_RATIO.1)? { - Ok(ArbitraryVec::Wrong(Arbitrary::arbitrary(u)?)) - } else { - Ok(ArbitraryVec::Good(Arbitrary::arbitrary(u)?)) - } - } - } - - impl SorobanArbitrary for Vec - where - T: SorobanArbitrary, - { - type Prototype = ArbitraryVec; - } - - impl TryFromVal> for Vec - where - T: SorobanArbitrary, - { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryVec) -> Result { - match v { - ArbitraryVec::Good(vec) => { - let mut buf: Vec = Vec::new(env); - for item in vec.iter() { - buf.push_back(item.into_val(env)); - } - Ok(buf) - } - ArbitraryVec::Wrong(vec) => { - let mut buf: Vec = Vec::new(env); - for item in vec.iter() { - buf.push_back(item.into_val(env)); - } - Ok(Vec::::from_val(env, &buf.to_val())) - } - } - } - } - - ////////////////////////////////// - - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryMap { - Good(RustVec<(K, V)>), - // Maps can be constructed with non-T K/Vs - WrongKey(RustVec<(ArbitraryVal, V)>), - WrongValue(RustVec<(K, ArbitraryVal)>), - } - - impl<'a, K, V> Arbitrary<'a> for ArbitraryMap - where - K: Arbitrary<'a>, - V: Arbitrary<'a>, - { - fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult> { - // How frequently we provide ArbitraryMap::Wrong* - const WRONG_TYPE_RATIO: (u16, u16) = (1, 1000); - - if u.ratio(WRONG_TYPE_RATIO.0, WRONG_TYPE_RATIO.1)? { - if u.arbitrary::()? { - Ok(ArbitraryMap::WrongKey(Arbitrary::arbitrary(u)?)) - } else { - Ok(ArbitraryMap::WrongValue(Arbitrary::arbitrary(u)?)) - } - } else { - Ok(ArbitraryMap::Good(Arbitrary::arbitrary(u)?)) - } - } - } - - impl SorobanArbitrary for Map - where - K: SorobanArbitrary, - V: SorobanArbitrary, - { - type Prototype = ArbitraryMap; - } - - impl TryFromVal> for Map - where - K: SorobanArbitrary, - V: SorobanArbitrary, - { - type Error = ConversionError; - fn try_from_val( - env: &Env, - v: &ArbitraryMap, - ) -> Result { - match v { - ArbitraryMap::Good(vec) => { - let mut map: Map = Map::new(env); - for (k, v) in vec.iter() { - map.set(k.into_val(env), v.into_val(env)); - } - Ok(map) - } - ArbitraryMap::WrongKey(vec) => { - let mut map: Map = Map::new(env); - for (k, v) in vec.iter() { - map.set(k.into_val(env), v.into_val(env)); - } - Ok(Map::::from_val(env, &map.to_val())) - } - ArbitraryMap::WrongValue(vec) => { - let mut map: Map = Map::new(env); - for (k, v) in vec.iter() { - map.set(k.into_val(env), v.into_val(env)); - } - Ok(Map::::from_val(env, &map.to_val())) - } - } - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryAddress { - inner: [u8; 32], - } - - impl SorobanArbitrary for Address { - type Prototype = ArbitraryAddress; - } - - impl TryFromVal for Address { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryAddress) -> Result { - use crate::env::xdr::{ContractId, Hash, ScAddress}; - - let sc_addr = ScVal::Address(ScAddress::Contract(ContractId(Hash(v.inner)))); - Ok(sc_addr.into_val(env)) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryMuxedAddress { - Address(ArbitraryAddress), - Muxed { ed25519: [u8; 32], id: u64 }, - } - - impl SorobanArbitrary for MuxedAddress { - type Prototype = ArbitraryMuxedAddress; - } - - impl TryFromVal for MuxedAddress { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryMuxedAddress) -> Result { - use crate::env::xdr::{MuxedEd25519Account, ScAddress, Uint256}; - - let sc_addr = match v { - ArbitraryMuxedAddress::Address(v) => { - let address = Address::try_from_val(env, v)?; - return Ok(address.into()); - } - ArbitraryMuxedAddress::Muxed { ed25519, id } => { - ScVal::Address(ScAddress::MuxedAccount(MuxedEd25519Account { - ed25519: Uint256(*ed25519), - id: *id, - })) - } - }; - Ok(sc_addr.into_val(env)) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryTimepoint { - inner: u64, - } - - impl SorobanArbitrary for Timepoint { - type Prototype = ArbitraryTimepoint; - } - - impl TryFromVal for Timepoint { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryTimepoint) -> Result { - let sc_timepoint = ScVal::Timepoint(crate::xdr::TimePoint::from(v.inner)); - Ok(sc_timepoint.into_val(env)) - } - } - - ////////////////////////////////// - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryDuration { - inner: u64, - } - - impl SorobanArbitrary for Duration { - type Prototype = ArbitraryDuration; - } - - impl TryFromVal for Duration { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryDuration) -> Result { - let sc_duration = ScVal::Duration(crate::xdr::Duration::from(v.inner)); - Ok(sc_duration.into_val(env)) - } - } - - // For Bls12381Fp (48 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBls12381Fp { - bytes: [u8; FP_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bls12381Fp { - type Prototype = ArbitraryBls12381Fp; - } - - impl TryFromVal for Bls12381Fp { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBls12381Fp) -> Result { - let mut bytes = v.bytes; - // Ensure the value is strictly less than the BLS12-381 base field modulus - // p = 0x1a0111ea... by restricting the most significant byte. - bytes[0] %= 0x1a; - Ok(Bls12381Fp::from_array(env, &bytes)) - } - } - - // For Bls12381Fp2 (96 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBls12381Fp2 { - bytes: [u8; FP2_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bls12381Fp2 { - type Prototype = ArbitraryBls12381Fp2; - } - - impl TryFromVal for Bls12381Fp2 { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBls12381Fp2) -> Result { - let mut bytes = v.bytes; - // Ensure both Fp components are strictly less than the modulus - bytes[0] %= 0x1a; - bytes[FP_SERIALIZED_SIZE] %= 0x1a; - Ok(Bls12381Fp2::from_array(env, &bytes)) - } - } - - // For Bls12381G1Affine (96 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBls12381G1Affine { - bytes: [u8; G1_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bls12381G1Affine { - type Prototype = ArbitraryBls12381G1Affine; - } - - impl TryFromVal for Bls12381G1Affine { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBls12381G1Affine) -> Result { - let mut bytes = v.bytes; - // the top 3 bits in a G1 point are reserved for flags: - // compression_flag (bit 0), infinity_flag (bit 1) and sort_flag - // (bit 2). Only infinity_flag is possible to be set, in which case - // the rest of the bytes must be zeros. The host will reject any - // invalid input. Manually taking care of the flag bits here to give - // it better chance of being a valid input. - const INFINITY_FLAG: u8 = 0b0100_0000; - const FLAG_MASK: u8 = 0b1110_0000; - if (bytes[0] & INFINITY_FLAG) != 0 { - // infinity flag set, clear rest of bits - bytes = [0; 96]; - bytes[0] = INFINITY_FLAG; - } else { - // not an infinity point, we clear the flag bits - bytes[0] &= !FLAG_MASK - } - Ok(Bls12381G1Affine::from_array(env, &bytes)) - } - } - - // For Bls12381G2Affine (192 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBls12381G2Affine { - bytes: [u8; G2_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bls12381G2Affine { - type Prototype = ArbitraryBls12381G2Affine; - } - - impl TryFromVal for Bls12381G2Affine { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBls12381G2Affine) -> Result { - let mut bytes = v.bytes; - // the top 3 bits in a G1 point are reserved for flags: - // compression_flag (bit 0), infinity_flag (bit 1) and sort_flag - // (bit 2). Only infinity_flag is possible to be set, in which case - // the rest of the bytes must be zeros. The host will reject any - // invalid input. Manually taking care of the flag bits here to give - // it better chance of being a valid input. - const INFINITY_FLAG: u8 = 0b0100_0000; - const FLAG_MASK: u8 = 0b1110_0000; - if (bytes[0] & INFINITY_FLAG) != 0 { - // infinity flag set, clear rest of bits - bytes = [0; 192]; - bytes[0] = INFINITY_FLAG; - } else { - // not an infinity point, we clear the flag bits - bytes[0] &= !FLAG_MASK - } - Ok(Bls12381G2Affine::from_array(env, &bytes)) - } - } - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBls12381Fr { - bytes: [u8; 32], - } - - impl SorobanArbitrary for Bls12381Fr { - type Prototype = ArbitraryBls12381Fr; - } - - impl TryFromVal for Bls12381Fr { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBls12381Fr) -> Result { - // Convert bytes to Bls12381Fr via U256 - Ok(Bls12381Fr::from_bytes(BytesN::from_array(env, &v.bytes))) - } - } - - // BN254 types - - // For BN254 G1Affine (64 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBn254G1Affine { - bytes: [u8; BN254_G1_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bn254G1Affine { - type Prototype = ArbitraryBn254G1Affine; - } - - impl TryFromVal for Bn254G1Affine { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBn254G1Affine) -> Result { - Ok(Bn254G1Affine::from_array(env, &v.bytes)) - } - } - - // For BN254 G2Affine (128 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBn254G2Affine { - bytes: [u8; BN254_G2_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bn254G2Affine { - type Prototype = ArbitraryBn254G2Affine; - } - - impl TryFromVal for Bn254G2Affine { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBn254G2Affine) -> Result { - Ok(Bn254G2Affine::from_array(env, &v.bytes)) - } - } - - // For Bn254Fp (32 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBn254Fp { - bytes: [u8; BN254_FP_SERIALIZED_SIZE], - } - - impl SorobanArbitrary for Bn254Fp { - type Prototype = ArbitraryBn254Fp; - } - - impl TryFromVal for Bn254Fp { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBn254Fp) -> Result { - let mut bytes = v.bytes; - // Ensure the value is strictly less than the BN254 base field modulus - // p = 0x30644e72... by restricting the most significant byte. - bytes[0] %= 0x30; - Ok(Bn254Fp::from_array(env, &bytes)) - } - } - - // For BN254 Fr (32 bytes) - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct ArbitraryBn254Fr { - bytes: [u8; 32], - } - - impl SorobanArbitrary for Bn254Fr { - type Prototype = ArbitraryBn254Fr; - } - - impl TryFromVal for Bn254Fr { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &ArbitraryBn254Fr) -> Result { - Ok(Bn254Fr::from_bytes(BytesN::from_array(env, &v.bytes))) - } - } -} - -/// Implementations of `soroban_sdk::testutils::arbitrary::api` for tuples of Soroban types. -/// -/// The implementation is similar to objects, but macroized. -mod tuples { - use super::api::*; - use crate::ConversionError; - use crate::{Env, IntoVal, TryFromVal, TryIntoVal, Val}; - use arbitrary::Arbitrary; - - macro_rules! impl_tuple { - ($name: ident, $($ty: ident),+ ) => { - #[allow(non_snake_case)] // naming fields T1, etc. - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub struct $name<$($ty,)*> { - $($ty: $ty,)* - } - - impl<$($ty,)*> SorobanArbitrary for ($($ty,)*) - where $($ty: SorobanArbitrary + TryIntoVal,)* - { - type Prototype = $name<$($ty::Prototype,)*>; - } - - impl<$($ty,)*> TryFromVal> for ($($ty,)*) - where $($ty: SorobanArbitrary,)* - { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &$name<$($ty::Prototype,)*>) -> Result { - Ok(($( - v.$ty.into_val(env), - )*)) - } - } - } - } - - impl_tuple!(ArbitraryTuple1, T1); - impl_tuple!(ArbitraryTuple2, T1, T2); - impl_tuple!(ArbitraryTuple3, T1, T2, T3); - impl_tuple!(ArbitraryTuple4, T1, T2, T3, T4); - impl_tuple!(ArbitraryTuple5, T1, T2, T3, T4, T5); - impl_tuple!(ArbitraryTuple6, T1, T2, T3, T4, T5, T6); - impl_tuple!(ArbitraryTuple7, T1, T2, T3, T4, T5, T6, T7); - impl_tuple!(ArbitraryTuple8, T1, T2, T3, T4, T5, T6, T7, T8); - impl_tuple!(ArbitraryTuple9, T1, T2, T3, T4, T5, T6, T7, T8, T9); - impl_tuple!(ArbitraryTuple10, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); - impl_tuple!( - ArbitraryTuple11, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11 - ); - impl_tuple!( - ArbitraryTuple12, - T1, - T2, - T3, - T4, - T5, - T6, - T7, - T8, - T9, - T10, - T11, - T12 - ); -} - -/// Implementations of `soroban_sdk::testutils::arbitrary::api` for `Val`. -mod composite { - use arbitrary::Arbitrary; - - use super::api::*; - use crate::ConversionError; - use crate::{Env, IntoVal, TryFromVal}; - - use super::objects::*; - use super::simple::*; - use crate::{ - Address, Bytes, BytesN, Duration, Map, String, Symbol, Timepoint, Val, Vec, I256, U256, - }; - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryVal { - Void, - Bool(bool), - Error(Error), - U32(u32), - I32(i32), - U64(u64), - I64(i64), - U128(u128), - I128(i128), - U256(ArbitraryU256), - I256(ArbitraryI256), - Bytes(ArbitraryBytes), - String(ArbitraryString), - Symbol(ArbitrarySymbol), - Vec(ArbitraryValVec), - Map(ArbitraryValMap), - Address(ArbitraryAddress), - Timepoint(ArbitraryTimepoint), - Duration(ArbitraryDuration), - Option(ArbitraryValOption), - } - - impl SorobanArbitrary for Val { - type Prototype = ArbitraryVal; - } - - impl TryFromVal for Val { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryVal) -> Result { - Ok(match v { - ArbitraryVal::Void => Val::VOID.into(), - ArbitraryVal::Bool(v) => v.into_val(env), - ArbitraryVal::Error(v) => v.into_val(env), - ArbitraryVal::U32(v) => v.into_val(env), - ArbitraryVal::I32(v) => v.into_val(env), - ArbitraryVal::U64(v) => v.into_val(env), - ArbitraryVal::I64(v) => v.into_val(env), - ArbitraryVal::U256(v) => { - let v: U256 = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::I256(v) => { - let v: I256 = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::U128(v) => v.into_val(env), - ArbitraryVal::I128(v) => v.into_val(env), - ArbitraryVal::Bytes(v) => { - let v: Bytes = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::String(v) => { - let v: String = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::Symbol(v) => { - let v: Symbol = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::Vec(v) => v.into_val(env), - ArbitraryVal::Map(v) => v.into_val(env), - ArbitraryVal::Address(v) => { - let v: Address = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::Timepoint(v) => { - let v: Timepoint = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::Duration(v) => { - let v: Duration = v.into_val(env); - v.into_val(env) - } - ArbitraryVal::Option(v) => v.into_val(env), - }) - } - } - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryValVec { - Void( as SorobanArbitrary>::Prototype), - Bool( as SorobanArbitrary>::Prototype), - Error( as SorobanArbitrary>::Prototype), - U32( as SorobanArbitrary>::Prototype), - I32( as SorobanArbitrary>::Prototype), - U64( as SorobanArbitrary>::Prototype), - I64( as SorobanArbitrary>::Prototype), - U128( as SorobanArbitrary>::Prototype), - I128( as SorobanArbitrary>::Prototype), - U256( as SorobanArbitrary>::Prototype), - I256( as SorobanArbitrary>::Prototype), - Bytes( as SorobanArbitrary>::Prototype), - BytesN(> as SorobanArbitrary>::Prototype), - String( as SorobanArbitrary>::Prototype), - Symbol( as SorobanArbitrary>::Prototype), - Vec(> as SorobanArbitrary>::Prototype), - Map(> as SorobanArbitrary>::Prototype), - Address( as SorobanArbitrary>::Prototype), - Timepoint( as SorobanArbitrary>::Prototype), - Duration( as SorobanArbitrary>::Prototype), - Val( as SorobanArbitrary>::Prototype), - } - - impl TryFromVal for Val { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryValVec) -> Result { - Ok(match v { - ArbitraryValVec::Void(v) => { - let v: Vec<()> = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Bool(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Error(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::U32(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::I32(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::U64(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::I64(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::U128(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::I128(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::U256(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::I256(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Bytes(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::BytesN(v) => { - let v: Vec> = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::String(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Symbol(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Vec(v) => { - let v: Vec> = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Map(v) => { - let v: Vec> = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Address(v) => { - let v: Vec
= v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Timepoint(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Duration(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - ArbitraryValVec::Val(v) => { - let v: Vec = v.into_val(env); - v.into_val(env) - } - }) - } - } - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryValMap { - VoidToVoid( as SorobanArbitrary>::Prototype), - BoolToBool( as SorobanArbitrary>::Prototype), - ErrorToError( as SorobanArbitrary>::Prototype), - U32ToU32( as SorobanArbitrary>::Prototype), - I32ToI32( as SorobanArbitrary>::Prototype), - U64ToU64( as SorobanArbitrary>::Prototype), - I64ToI64( as SorobanArbitrary>::Prototype), - U128ToU128( as SorobanArbitrary>::Prototype), - I128ToI128( as SorobanArbitrary>::Prototype), - U256ToU256( as SorobanArbitrary>::Prototype), - I256ToI256( as SorobanArbitrary>::Prototype), - BytesToBytes( as SorobanArbitrary>::Prototype), - BytesNToBytesN(, BytesN<32>> as SorobanArbitrary>::Prototype), - StringToString( as SorobanArbitrary>::Prototype), - SymbolToSymbol( as SorobanArbitrary>::Prototype), - VecToVec(, Vec> as SorobanArbitrary>::Prototype), - MapToMap(, Map> as SorobanArbitrary>::Prototype), - AddressToAddress( as SorobanArbitrary>::Prototype), - TimepointToTimepoint( as SorobanArbitrary>::Prototype), - DurationToDuration( as SorobanArbitrary>::Prototype), - ValToVal( as SorobanArbitrary>::Prototype), - OptionToOption(, Option> as SorobanArbitrary>::Prototype), - } - - impl TryFromVal for Val { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryValMap) -> Result { - Ok(match v { - ArbitraryValMap::VoidToVoid(v) => { - let v: Map<(), ()> = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::BoolToBool(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::ErrorToError(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::U32ToU32(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::I32ToI32(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::U64ToU64(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::I64ToI64(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::U128ToU128(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::I128ToI128(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::U256ToU256(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::I256ToI256(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::BytesToBytes(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::BytesNToBytesN(v) => { - let v: Map, BytesN<32>> = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::StringToString(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::SymbolToSymbol(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::VecToVec(v) => { - let v: Map, Vec> = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::MapToMap(v) => { - let v: Map, Map> = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::AddressToAddress(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::TimepointToTimepoint(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::DurationToDuration(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::ValToVal(v) => { - let v: Map = v.into_val(env); - v.into_val(env) - } - ArbitraryValMap::OptionToOption(v) => { - let v: Map, Option> = v.into_val(env); - v.into_val(env) - } - }) - } - } - - #[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] - pub enum ArbitraryValOption { - Void( as SorobanArbitrary>::Prototype), - Bool( as SorobanArbitrary>::Prototype), - Error( as SorobanArbitrary>::Prototype), - U32( as SorobanArbitrary>::Prototype), - I32( as SorobanArbitrary>::Prototype), - U64( as SorobanArbitrary>::Prototype), - I64( as SorobanArbitrary>::Prototype), - U128( as SorobanArbitrary>::Prototype), - I128( as SorobanArbitrary>::Prototype), - U256( as SorobanArbitrary>::Prototype), - I256( as SorobanArbitrary>::Prototype), - Bytes( as SorobanArbitrary>::Prototype), - BytesN(> as SorobanArbitrary>::Prototype), - String( as SorobanArbitrary>::Prototype), - Symbol( as SorobanArbitrary>::Prototype), - Vec(> as SorobanArbitrary>::Prototype), - Map(> as SorobanArbitrary>::Prototype), - Address( as SorobanArbitrary>::Prototype), - Timepoint( as SorobanArbitrary>::Prototype), - Duration( as SorobanArbitrary>::Prototype), - Val(Box< as SorobanArbitrary>::Prototype>), - } - - impl TryFromVal for Val { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &ArbitraryValOption) -> Result { - Ok(match v { - ArbitraryValOption::Void(v) => { - let v: Option<()> = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Bool(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Error(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::U32(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::I32(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::U64(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::I64(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::U128(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::I128(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::U256(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::I256(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Bytes(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::BytesN(v) => { - let v: Option> = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::String(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Symbol(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Vec(v) => { - let v: Option> = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Map(v) => { - let v: Option> = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Address(v) => { - let v: Option
= v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Timepoint(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Duration(v) => { - let v: Option = v.into_val(env); - v.into_val(env) - } - ArbitraryValOption::Val(v) => { - let v: Option = (**v).into_val(env); - v.into_val(env) - } - }) - } - } -} - -/// Additional tools for writing fuzz tests. -mod fuzz_test_helpers { - use soroban_env_host::testutils::call_with_suppressed_panic_hook; - - /// Catch panics within a fuzz test. - /// - /// The `cargo-fuzz` test harness turns panics into test failures, - /// immediately aborting the process. - /// - /// This function catches panics while temporarily disabling the - /// `cargo-fuzz` panic handler. - /// - /// # Example - /// - /// ``` - /// # macro_rules! fuzz_target { - /// # (|$data:ident: $dty: ty| $body:block) => { }; - /// # } - /// # struct ExampleContract; - /// # impl ExampleContract { - /// # fn new(e: &soroban_sdk::Env, b: &soroban_sdk::BytesN<32>) { } - /// # fn deposit(&self, a: soroban_sdk::Address, n: i128) { } - /// # } - /// use soroban_sdk::{Address, Env}; - /// use soroban_sdk::testutils::arbitrary::{Arbitrary, SorobanArbitrary}; - /// - /// #[derive(Arbitrary, Debug)] - /// struct FuzzDeposit { - /// deposit_amount: i128, - /// deposit_address:
::Prototype, - /// } - /// - /// fuzz_target!(|input: FuzzDeposit| { - /// let env = Env::default(); - /// - /// let contract = ExampleContract::new(env, &env.register_contract(None, ExampleContract {})); - /// - /// let addresses: Address = input.deposit_address.into_val(&env); - /// let r = contract.try_deposit(deposit_address, input.deposit_amount); - /// }); - /// ``` - #[deprecated(note = "use [Env::try_invoke] or the try_ functions on a contract client")] - pub fn fuzz_catch_panic(f: F) -> std::thread::Result - where - F: FnOnce() -> R, - { - call_with_suppressed_panic_hook(std::panic::AssertUnwindSafe(f)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - Address, Bytes, BytesN, Duration, Error, Map, String, Symbol, Timepoint, Val, Vec, I256, - U256, - }; - use crate::{Env, IntoVal}; - use arbitrary::{Arbitrary, Unstructured}; - use rand::{RngCore, SeedableRng}; - - fn run_test() - where - T: SorobanArbitrary, - T::Prototype: for<'a> Arbitrary<'a>, - { - let env = Env::default(); - let mut rng = rand::rngs::StdRng::seed_from_u64(0); - let mut rng_data = [0u8; 64]; - - for _ in 0..100 { - rng.fill_bytes(&mut rng_data); - let mut unstructured = Unstructured::new(&rng_data); - loop { - match T::Prototype::arbitrary(&mut unstructured) { - Ok(input) => { - let _val: T = input.into_val(&env); - break; - } - Err(_) => {} - } - } - } - } - - #[test] - fn test_unit() { - run_test::<()>() - } - - #[test] - fn test_bool() { - run_test::() - } - - #[test] - fn test_u32() { - run_test::() - } - - #[test] - fn test_i32() { - run_test::() - } - - #[test] - fn test_u64() { - run_test::() - } - - #[test] - fn test_i64() { - run_test::() - } - - #[test] - fn test_u128() { - run_test::() - } - - #[test] - fn test_i128() { - run_test::() - } - - #[test] - fn test_u256() { - run_test::() - } - - #[test] - fn test_i256() { - run_test::() - } - - #[test] - fn test_bytes() { - run_test::() - } - - #[test] - fn test_string() { - run_test::() - } - - #[test] - fn test_bytes_n() { - run_test::>() - } - - #[test] - fn test_symbol() { - run_test::() - } - - #[test] - fn test_address() { - run_test::
() - } - - #[test] - fn test_val() { - run_test::() - } - - #[test] - fn test_vec_void() { - run_test::>() - } - - #[test] - fn test_vec_bool() { - run_test::>() - } - - #[test] - fn test_vec_error() { - run_test::>() - } - - #[test] - fn test_vec_u32() { - run_test::>() - } - - #[test] - fn test_vec_i32() { - run_test::>() - } - - #[test] - fn test_vec_u64() { - run_test::>() - } - - #[test] - fn test_vec_i64() { - run_test::>() - } - - #[test] - fn test_vec_u128() { - run_test::>() - } - - #[test] - fn test_vec_i128() { - run_test::>() - } - - #[test] - fn test_vec_u256() { - run_test::>() - } - - #[test] - fn test_vec_i256() { - run_test::>() - } - - #[test] - fn test_vec_bytes() { - run_test::>() - } - - #[test] - fn test_vec_bytes_n() { - run_test::>>() - } - - #[test] - fn test_vec_string() { - run_test::>() - } - - #[test] - fn test_vec_symbol() { - run_test::>() - } - - #[test] - fn test_vec_vec_u32() { - run_test::>>() - } - - #[test] - fn test_vec_vec_bytes() { - run_test::>>() - } - - #[test] - fn test_vec_timepoint() { - run_test::>() - } - - #[test] - fn test_vec_duration() { - run_test::>() - } - - #[test] - fn test_vec_map_u32() { - run_test::>>() - } - - #[test] - fn test_vec_address() { - run_test::>() - } - - #[test] - fn test_vec_val() { - run_test::>() - } - - #[test] - fn test_map_void() { - run_test::>() - } - - #[test] - fn test_map_bool() { - run_test::>() - } - - #[test] - fn test_map_error() { - run_test::>() - } - - #[test] - fn test_map_u32() { - run_test::>>() - } - - #[test] - fn test_map_i32() { - run_test::>>() - } - - #[test] - fn test_map_u64() { - run_test::>>() - } - - #[test] - fn test_map_i64() { - run_test::>>() - } - - #[test] - fn test_map_u128() { - run_test::>>() - } - - #[test] - fn test_map_i128() { - run_test::>>() - } - - #[test] - fn test_map_u256() { - run_test::>>() - } - - #[test] - fn test_map_i256() { - run_test::>>() - } - - #[test] - fn test_map_bytes() { - run_test::>() - } - - #[test] - fn test_map_bytes_n() { - run_test::, Bytes>>() - } - - #[test] - fn test_map_string() { - run_test::>() - } - - #[test] - fn test_map_symbol() { - run_test::>() - } - - #[test] - fn test_map_vec_u32() { - run_test::, Vec>>() - } - - #[test] - fn test_map_vec_bytes() { - run_test::, Vec>>() - } - - #[test] - fn test_map_timepoint() { - run_test::>() - } - - #[test] - fn test_map_duration() { - run_test::>() - } - - fn test_map_map_u32() { - run_test::, Map>>() - } - - #[test] - fn test_map_address() { - run_test::>() - } - - #[test] - fn test_map_val() { - run_test::>() - } - - #[test] - fn test_timepoint() { - run_test::() - } - - #[test] - fn test_duration() { - run_test::() - } - - #[test] - fn test_tuples() { - run_test::<(u32,)>(); - run_test::<(u32, u32)>(); - run_test::<(u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); - run_test::<(u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32)>(); - - run_test::<(u32, Address, Vec, Map)>(); - } - - #[test] - fn test_option() { - run_test::>(); - run_test::>>(); - } - - // Test that sometimes generated vecs have the wrong element types. - #[test] - fn test_vec_wrong_types() { - // These number are tuned for StdRng. - // If StdRng ever changes the test could break. - let iterations = 1000; - let seed = 3; - let acceptable_ratio = 900; - - let (mut seen_good, mut seen_bad, mut seen_empty) = (0, 0, 0); - - let env = Env::default(); - let mut rng = rand::rngs::StdRng::seed_from_u64(seed); - let mut rng_data = [0u8; 64]; - - for _ in 0..iterations { - rng.fill_bytes(&mut rng_data); - let mut unstructured = Unstructured::new(&rng_data); - let input = as SorobanArbitrary>::Prototype::arbitrary(&mut unstructured) - .expect("SorobanArbitrary"); - let vec: Vec = input.into_val(&env); - - let has_good_elts = (0..vec.len()).all(|i| vec.try_get(i).is_ok()) && !vec.is_empty(); - // Look for elements that cause an error. - let has_bad_elt = (0..vec.len()).any(|i| vec.try_get(i).is_err()); - - if has_bad_elt { - seen_bad += 1; - } else if has_good_elts { - seen_good += 1; - } else { - seen_empty += 1; - } - } - - assert!(seen_good > 0); - assert!(seen_bad > 0); - - // sanity check the ratio of good to bad - assert!(seen_good * seen_empty > seen_bad * acceptable_ratio); - } - - // Test that sometimes generated maps have the wrong element types. - #[test] - fn test_map_wrong_types() { - // These number are tuned for StdRng. - // If StdRng ever changes the test could break. - let iterations = 4000; - let seed = 13; - let acceptable_ratio = 900; - - let (mut seen_good, mut seen_bad_key, mut seen_bad_value, mut seen_empty) = (0, 0, 0, 0); - - let env = Env::default(); - let mut rng = rand::rngs::StdRng::seed_from_u64(seed); - let mut rng_data = [0u8; 128]; - - for _ in 0..iterations { - rng.fill_bytes(&mut rng_data); - let mut unstructured = Unstructured::new(&rng_data); - let input = - as SorobanArbitrary>::Prototype::arbitrary(&mut unstructured) - .expect("SorobanArbitrary"); - let map: Map = input.into_val(&env); - - // Look for elements that cause an error. - let keys = map.keys(); - let values = map.values(); - - let has_good_keys = - (0..keys.len()).all(|i| keys.try_get(i).is_ok()) && !keys.is_empty(); - let has_good_values = - (0..values.len()).all(|i| values.try_get(i).is_ok()) && !keys.is_empty(); - let has_bad_key = (0..keys.len()).any(|i| keys.try_get(i).is_err()); - let has_bad_value = (0..values.len()).any(|i| values.try_get(i).is_err()); - - if has_bad_key { - seen_bad_key += 1; - } else if has_bad_value { - seen_bad_value += 1; - } else if has_good_keys && has_good_values { - seen_good += 1; - } else { - seen_empty += 1; - } - } - - assert!(seen_good > 0); - assert!(seen_bad_key > 0); - assert!(seen_bad_value > 0); - - // sanity check the ratio of good to bad - assert!(seen_good * seen_empty > (seen_bad_key + seen_bad_value) * acceptable_ratio); - } - - mod user_defined_types { - use super::run_test; - use crate as soroban_sdk; - use crate::{ - Address, Bytes, BytesN, Duration, Error, Map, Symbol, Timepoint, Vec, I256, U256, - }; - use soroban_sdk::contracttype; - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - struct PrivStruct { - count_u: u32, - count_i: i32, - bytes_n: BytesN<32>, - vec: Vec, - map: Map>, - u256: U256, - i156: I256, - error: Error, - address: Address, - symbol: Symbol, - duration: Duration, - timepoint: Timepoint, - nil: (), - vec_tuple: Vec<(u32, Address)>, - option: Option, - } - - #[test] - fn test_user_defined_priv_struct() { - run_test::(); - } - - #[test] - fn test_option_user_defined_priv_struct() { - run_test::>(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - struct PrivStructPubFields { - pub count_u: u32, - pub count_i: i32, - pub bytes_n: BytesN<32>, - pub vec: Vec, - pub map: Map>, - } - - #[test] - fn test_user_defined_priv_struct_pub_fields() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub struct PubStruct { - count_u: u32, - count_i: i32, - bytes_n: BytesN<32>, - vec: Vec, - map: Map>, - } - - #[test] - fn test_user_defined_pub_struct() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub struct PubStructPubFields { - pub count_u: u32, - pub count_i: i32, - pub bytes_n: BytesN<32>, - pub vec: Vec, - pub map: Map>, - } - - #[test] - fn test_user_defined_pubstruct_pub_fields() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - struct PrivTupleStruct( - u32, - i32, - BytesN<32>, - Vec, - Map>, - Vec<(u32, Address)>, - Option, - ); - - #[test] - fn test_user_defined_priv_tuple_struct() { - run_test::(); - } - - #[test] - fn test_option_user_defined_priv_tuple_struct() { - run_test::>(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - struct PrivTupleStructPubFields( - pub u32, - pub i32, - pub BytesN<32>, - pub Vec, - pub Map>, - pub Vec<(u32, Address)>, - ); - - #[test] - fn test_user_defined_priv_tuple_struct_pub_fields() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub struct PubTupleStruct(u32, i32, BytesN<32>, Vec, Map>); - - #[test] - fn test_user_defined_pub_tuple_struct() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub struct PubTupleStructPubFields( - pub u32, - pub i32, - pub BytesN<32>, - pub Vec, - pub Map>, - pub Vec<(u32, Address)>, - ); - - #[test] - fn test_user_defined_pub_tuple_struct_pub_fields() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub(crate) struct PubCrateStruct(u32); - - #[test] - fn test_user_defined_pub_crate_struct() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - enum PrivEnum { - A(u32), - Aa(u32, u32), - C, - D, - E(Vec<(u32, Address)>), - F(Option), - } - - #[test] - fn test_user_defined_priv_enum() { - run_test::(); - } - - #[test] - fn test_option_user_defined_priv_enum() { - run_test::>(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub enum PubEnum { - A(u32), - C, - D, - } - - #[test] - fn test_user_defined_pub_enum() { - run_test::(); - } - - #[contracttype] - #[derive(Clone, Debug, Eq, PartialEq)] - pub(crate) enum PubCrateEnum { - A(u32), - C, - D, - } - - #[test] - fn test_user_defined_pub_crate_enum() { - run_test::(); - } - - #[contracttype] - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - enum PrivEnumInt { - A = 1, - C = 2, - D = 3, - } - - #[test] - fn test_user_defined_priv_enum_int() { - run_test::(); - } - - #[contracttype] - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - pub enum PubEnumInt { - A = 1, - C = 2, - D = 3, - } - - #[test] - fn test_user_defined_pub_enum_int() { - run_test::(); - } - - #[test] - fn test_declared_inside_a_fn() { - #[contracttype] - struct Foo { - a: u32, - } - - #[contracttype] - enum Bar { - Baz, - Qux, - } - - run_test::(); - run_test::(); - } - - fn test_structs_and_enums_inside_tuples() { - #[contracttype] - struct Foo(u32); - - #[contracttype] - enum Bar { - Baz, - } - - run_test::<(Foo, Bar)>(); - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs deleted file mode 100644 index a1e9e54..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/testutils/cost_estimate.rs +++ /dev/null @@ -1,153 +0,0 @@ -use soroban_env_host::{ - fees::FeeConfiguration, FeeEstimate, InvocationResourceLimits, InvocationResources, -}; - -use crate::{testutils::budget::Budget, Env}; - -pub struct CostEstimate { - env: Env, -} - -impl CostEstimate { - pub(crate) fn new(env: Env) -> Self { - Self { env } - } - - /// Returns the resources metered during the last top level contract - /// invocation. - /// Take the return value with a grain of salt. The returned resources mostly - /// correspond only to the operations that have happened during the host - /// invocation, i.e. this won't try to simulate the work that happens in - /// production scenarios (e.g. certain XDR rountrips). This also doesn't try - /// to model resources related to the transaction size. - /// - /// The returned value is as useful as the preceding setup, e.g. if a test - /// contract is used instead of a Wasm contract, all the costs related to - /// VM instantiation and execution, as well as Wasm reads/rent bumps will be - /// missed. - pub fn resources(&self) -> InvocationResources { - if let Some(res) = self.env.host().get_last_invocation_resources() { - res - } else { - panic!("Invocation cost estimate is not available. Make sure invocation cost metering is enabled in the EnvTestConfig and this is called after an invocation.") - } - } - - /// Estimates the fee for the last invocation's resources, i.e. the - /// resources returned by `resources()`. - /// - /// The fees are computed using the snapshot of the Stellar Pubnet fees made - /// on 2024-12-11. - /// - /// Take the return value with a grain of salt as both the resource estimate - /// and the fee rates may be imprecise. - /// - /// The returned value is as useful as the preceding setup, e.g. if a test - /// contract is used instead of a Wasm contract, all the costs related to - /// VM instantiation and execution, as well as Wasm reads/rent bumps will be - /// missed. - pub fn fee(&self) -> FeeEstimate { - // This is a snapshot of the fees as of 2024-12-11 with slight - // adjustments for p23. - // This has to be updated before p23 goes live with the configuration - // used at the network upgrade time. - let pubnet_fee_config = FeeConfiguration { - fee_per_instruction_increment: 25, - fee_per_disk_read_entry: 6250, - fee_per_write_entry: 10000, - fee_per_disk_read_1kb: 1786, - fee_per_write_1kb: 3500, - fee_per_historical_1kb: 16235, - fee_per_contract_event_1kb: 10000, - fee_per_transaction_size_1kb: 1624, - }; - let pubnet_persistent_rent_rate_denominator = 2103; - let pubnet_temp_rent_rate_denominator = 4206; - // This is a bit higher than the current network fee, it's an - // overestimate for the sake of providing a bit more conservative - // results in case if the state grows. - let fee_per_rent_1kb = 12000; - self.resources().estimate_fees( - &pubnet_fee_config, - fee_per_rent_1kb, - pubnet_persistent_rent_rate_denominator, - pubnet_temp_rent_rate_denominator, - ) - } - - /// Returns the budget object that provides the detailed CPU and memory - /// metering information recorded thus far. - /// - /// The budget metering resets before every top-level contract level - /// invocation. - /// - /// budget() may also be used to adjust the CPU and memory limits via the - /// `reset_` methods. - /// - /// Note, that unlike `resources()`/`fee()` this will always return some - /// value. If there was no contract call, then the resulting value will - /// correspond to metering any environment setup that has been made thus - /// far. - pub fn budget(&self) -> Budget { - Budget::new(self.env.host().budget_cloned()) - } - - /// Enforces custom resource limits for contract invocations in tests. - /// - /// When limit enforcement is enabled, for every contract invocation the - /// resource usage is checked against the provided limits, and if any of the - /// limits is exceeded, the contract invocation will result in a panic - /// that indicates which limits were exceeded. - /// - /// Limit enforcement is meant to provide an early warning sign that a - /// contract might be too resource heavy to run on a real network. If the - /// high resource usage is intentional and expected (e.g. for - /// experimentation), disable the enforcement via - /// `disable_resource_limits()`. - /// - /// By default, `InvocationResourceLimits::mainnet()` limits are enforced. - pub fn enforce_resource_limits(&self, limits: InvocationResourceLimits) { - self.env - .host() - .set_invocation_resource_limits(Some(limits)) - .unwrap(); - } - - /// Disables resource limit enforcement for contract invocations in tests. - /// - /// This may be useful for the experimental contracts that are still being - /// optimized. - pub fn disable_resource_limits(&self) { - self.env - .host() - .set_invocation_resource_limits(None) - .unwrap(); - } -} - -/// Predefined network invocation resource limits. -pub trait NetworkInvocationResourceLimits { - fn mainnet() -> Self; -} - -impl NetworkInvocationResourceLimits for InvocationResourceLimits { - /// Returns the invocation resource limits used on Stellar Mainnet. - /// - /// This is not pulling the values dynamically, so updating the SDK is - /// necessary to pick up the most recent values. - fn mainnet() -> Self { - InvocationResourceLimits { - instructions: 600_000_000, - mem_bytes: 41943040, - disk_read_entries: 100, - write_entries: 50, - ledger_entries: 100, - disk_read_bytes: 200000, - write_bytes: 132096, - contract_events_size_bytes: 16384, - max_contract_data_key_size_bytes: 250, - max_contract_data_entry_size_bytes: 65536, - max_contract_code_entry_size_bytes: 131072, - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs deleted file mode 100644 index ba2446d..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/testutils/mock_auth.rs +++ /dev/null @@ -1,145 +0,0 @@ -#![cfg(any(test, feature = "testutils"))] - -use crate::{contract, contractimpl, xdr, Address, Env, Symbol, TryFromVal, Val, Vec}; - -#[doc(hidden)] -#[contract(crate_path = "crate")] -pub struct MockAuthContract; - -#[contractimpl(crate_path = "crate")] -impl MockAuthContract { - #[allow(non_snake_case)] - pub fn __check_auth(_signature_payload: Val, _signatures: Val, _auth_context: Val) {} -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct MockAuth<'a> { - pub address: &'a Address, - pub invoke: &'a MockAuthInvoke<'a>, -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct MockAuthInvoke<'a> { - pub contract: &'a Address, - pub fn_name: &'a str, - pub args: Vec, - pub sub_invokes: &'a [MockAuthInvoke<'a>], -} - -impl<'a> From<&MockAuth<'a>> for xdr::SorobanAuthorizationEntry { - fn from(value: &MockAuth) -> Self { - let env = value.address.env(); - let curr_ledger = env.ledger().sequence(); - let max_entry_ttl = env.storage().max_ttl(); - Self { - root_invocation: value.invoke.into(), - credentials: xdr::SorobanCredentials::Address(xdr::SorobanAddressCredentials { - address: value.address.try_into().unwrap(), - nonce: env.with_generator(|mut g| g.nonce()), - signature_expiration_ledger: curr_ledger + max_entry_ttl, - signature: xdr::ScVal::Void, - }), - } - } -} - -impl<'a> From> for xdr::SorobanAuthorizationEntry { - fn from(value: MockAuth<'a>) -> Self { - (&value).into() - } -} - -impl<'a> From<&MockAuthInvoke<'a>> for xdr::SorobanAuthorizedInvocation { - fn from(value: &MockAuthInvoke<'a>) -> Self { - Self { - function: xdr::SorobanAuthorizedFunction::ContractFn(xdr::InvokeContractArgs { - contract_address: xdr::ScAddress::Contract(value.contract.contract_id()), - function_name: value.fn_name.try_into().unwrap(), - args: value.args.clone().try_into().unwrap(), - }), - sub_invocations: value - .sub_invokes - .iter() - .map(Into::<_>::into) - .collect::>() - .try_into() - .unwrap(), - } - } -} - -impl<'a> From> for xdr::SorobanAuthorizedInvocation { - fn from(value: MockAuthInvoke<'a>) -> Self { - (&value).into() - } -} - -/// Describes an authorized invocation tree from the perspective of a single -/// address. -/// -/// The authorized invocation tree for a given address is different from a -/// regular call tree: it only has nodes for the contract calls that called -/// `require_auth[_for_args]` for that address. -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct AuthorizedInvocation { - /// Function that has called `require_auth`. - pub function: AuthorizedFunction, - /// Authorized invocations originating from `function`. - pub sub_invocations: std::vec::Vec, -} - -/// A single node in `AuthorizedInvocation` tree. -#[derive(Clone, Eq, PartialEq, Debug)] -pub enum AuthorizedFunction { - /// Contract function defined by the contract address, function name and - /// `require_auth[_for_args]` arguments (these don't necessarily need to - /// match the actual invocation arguments). - Contract((Address, Symbol, Vec)), - /// Create contract host function with arguments specified as the respective - /// XDR. - CreateContractHostFn(xdr::CreateContractArgs), - /// Create contract host function with arguments specified as the respective - /// XDR. Supports passing constructor arguments. - CreateContractV2HostFn(xdr::CreateContractArgsV2), -} - -impl AuthorizedFunction { - pub fn from_xdr(env: &Env, v: &xdr::SorobanAuthorizedFunction) -> Self { - match v { - xdr::SorobanAuthorizedFunction::ContractFn(contract_fn) => { - let mut args = Vec::new(env); - for v in contract_fn.args.iter() { - args.push_back(Val::try_from_val(env, v).unwrap()); - } - Self::Contract(( - Address::try_from_val( - env, - &xdr::ScVal::Address(contract_fn.contract_address.clone()), - ) - .unwrap(), - Symbol::try_from_val(env, &contract_fn.function_name).unwrap(), - args, - )) - } - xdr::SorobanAuthorizedFunction::CreateContractHostFn(create_contract) => { - Self::CreateContractHostFn(create_contract.clone()) - } - xdr::SorobanAuthorizedFunction::CreateContractV2HostFn(create_contract) => { - Self::CreateContractV2HostFn(create_contract.clone()) - } - } - } -} - -impl AuthorizedInvocation { - pub fn from_xdr(env: &Env, v: &xdr::SorobanAuthorizedInvocation) -> Self { - Self { - function: AuthorizedFunction::from_xdr(env, &v.function), - sub_invocations: v - .sub_invocations - .iter() - .map(|si| AuthorizedInvocation::from_xdr(env, si)) - .collect(), - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs deleted file mode 100644 index 8d62833..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/testutils/sign.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![cfg(any(test, feature = "testutils"))] - -/// Sign implementations produce signatures for types that can be represented as -/// the MSG. -pub trait Sign { - type Signature; - type Error; - /// Sign produces a signature for MSGs. - fn sign(&self, m: MSG) -> Result; -} - -// TODO: Add a Verify interface and ed25519 implementation to counter the Sign -// interface. - -pub mod ed25519 { - use crate::xdr; - use xdr::{Limited, Limits, WriteXdr}; - - #[derive(Debug)] - pub enum Error { - XdrError(xdr::Error), - Ed25519SignatureError(ed25519_dalek::SignatureError), - ConversionError(E), - } - - impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::XdrError(e) => e.source(), - Self::Ed25519SignatureError(e) => e.source(), - Self::ConversionError(e) => e.source(), - } - } - } - - impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::XdrError(e) => write!(f, "{}", e), - Self::Ed25519SignatureError(e) => write!(f, "{}", e), - Self::ConversionError(e) => write!(f, "{}", e), - } - } - } - - impl From for Error { - fn from(e: xdr::Error) -> Self { - Error::XdrError(e) - } - } - - impl From for Error { - fn from(e: ed25519_dalek::SignatureError) -> Self { - Error::Ed25519SignatureError(e) - } - } - - pub use super::Sign; - - impl Sign for S - where - S: ed25519_dalek::Signer, - M: TryInto, - >::Error: std::error::Error, - { - type Error = Error<>::Error>; - type Signature = [u8; 64]; - fn sign(&self, m: M) -> Result { - let mut buf = Vec::::new(); - let val: xdr::ScVal = m.try_into().map_err(Self::Error::ConversionError)?; - val.write_xdr(&mut Limited::new(&mut buf, Limits::none()))?; - Ok(self.try_sign(&buf)?.to_bytes()) - } - } - - #[cfg(test)] - mod test { - use super::Sign; - use ed25519_dalek::SigningKey; - - #[test] - fn sign() { - let sk = SigningKey::from_bytes( - &hex::decode("5acc7253295dfc356c046297925a369f3d2762d00afdf2583ecbe92180b07c37") - .unwrap() - .try_into() - .unwrap(), - ); - let sig = sk.sign(128i64).unwrap(); - assert_eq!( - hex::encode(sig), - // Verified with https://go.dev/play/p/XiK8sOmvPsh - "a9b9dfac10bc1e5c8bc565e9515e5d086e3264b71bf4daf2c7340e1d10fae86e2563fa1d639ff153559a9710dfa270a9462fe87faa0e18a7a54a8a1a6151e909", - ); - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs deleted file mode 100644 index 41a9cc2..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/testutils/storage.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{Env, IntoVal, Map, Val}; - -/// Test utilities for [`Persistent`][crate::storage::Persistent]. -pub trait Persistent { - /// Returns all data stored in persistent storage for the contract. - fn all(&self) -> Map; - - /// Gets the TTL for the persistent storage entry corresponding to the provided key. - /// - /// TTL is the number of ledgers left until the persistent entry is considered - /// expired, excluding the current ledger. - /// - /// Panics if there is no entry corresponding to the key, or if the entry has expired. - fn get_ttl>(&self, key: &K) -> u32; -} - -/// Test utilities for [`Temporary`][crate::storage::Temporary]. -pub trait Temporary { - /// Returns all data stored in temporary storage for the contract. - fn all(&self) -> Map; - - /// Gets the TTL for the temporary storage entry corresponding to the provided key. - /// - /// TTL is the number of ledgers left until the temporary entry is considered - /// non-existent, excluding the current ledger. - /// - /// Panics if there is no entry corresponding to the key. - fn get_ttl>(&self, key: &K) -> u32; -} - -/// Test utilities for [`Instance`][crate::storage::Instance]. -pub trait Instance { - /// Returns all data stored in Instance storage for the contract. - fn all(&self) -> Map; - - /// Gets the TTL for the current contract's instance entry. - /// - /// TTL is the number of ledgers left until the instance entry is considered - /// expired, excluding the current ledger. - fn get_ttl(&self) -> u32; -} diff --git a/temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md b/temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md deleted file mode 100644 index 0e8b3a0..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/test_wasms/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# test_wasms - -Files contained in this directory are used in a few SDK tests that are sensitive -to Wasm content changes. - -`test_contract_data.wasm` is a build of `tests/contract_data` test contract. From 19b30070ae3e1974cdc60b9c697e1f8140edce70 Mon Sep 17 00:00:00 2001 From: Qoder-Undefined Date: Thu, 23 Jul 2026 16:57:38 +0100 Subject: [PATCH 3/4] fixes --- .../src/_migrating/v23_archived_testing.rs | 176 --- .../src/_migrating/v23_contractevent.rs | 438 ------- .../src/_migrating/v25_bn254.rs | 138 -- .../src/_migrating/v25_contracttrait.rs | 335 ----- .../src/_migrating/v25_event_testing.rs | 154 --- .../src/_migrating/v25_poseidon.rs | 100 -- .../src/_migrating/v25_resource_limits.rs | 145 --- .../src/crypto/bls12_381.rs | 1123 ----------------- .../soroban-sdk-26.0.1/src/crypto/bn254.rs | 727 ----------- .../soroban-sdk-26.0.1/src/crypto/utils.rs | 64 - 10 files changed, 3400 deletions(-) delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs deleted file mode 100644 index 788b57c..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_archived_testing.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! Accessing archived persistent entries in tests no longer results in an error. -//! -//! Prior to protocol 23 the SDK used to emulate the failure when an archived -//! ledger entry was accessed in tests. This behavior has never represented the -//! actual behavior of the network, just one possible scenario when an archived -//! entry is present in the transaction footprint. -//! -//! In protocol 23 automatic entry restoration has been introduced, which makes -//! it possible for a transaction to restore an archived entry before accessing -//! it. As this behavior will become the most common case on the network, the -//! SDK has been changed to emulate automatic restoration in tests as well. -//! -//! Note, that instance storage is a persistent entry as well, so it is subject -//! to the same change. -//! -//! ## Example -//! -//! Consider the following simple contract that extends entry TTL -//! along with the test that relies on the error on archived entry access in -//! SDK 22: -//! -//! ``` -//! #![no_std] -//! use soroban_sdk::{contract, contractimpl, contracttype, Env}; -//! -//! #[contract] -//! struct Contract; -//! -//! #[contracttype] -//! enum DataKey { -//! Key, -//! } -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn create_and_extend_entry(env: Env) { -//! env.storage().persistent().set(&DataKey::Key, &123_u32); -//! // Extend the entry to live for at least 1_000_000 ledgers. -//! env.storage() -//! .persistent() -//! .extend_ttl(&DataKey::Key, 1_000_000, 1_000_000); -//! } -//! -//! pub fn read_entry(env: Env) -> u32 { -//! env.storage().persistent().get(&DataKey::Key).unwrap() -//! } -//! } -//! -//! mod test { -//! extern crate std; -//! use soroban_sdk::testutils::{storage::Persistent, Ledger}; -//! -//! use super::*; -//! -//! #[test] -//! fn test_entry_archived() { -//! let env = Env::default(); -//! let contract = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract); -//! client.create_and_extend_entry(); -//! let current_ledger = env.ledger().sequence(); -//! assert_eq!(client.read_entry(), 123); -//! -//! // Bump ledger sequence past entry TTL. -//! env.ledger() -//! .set_sequence_number(current_ledger + 1_000_000 + 1); -//! let res = client.try_read_entry(); -//! // 👀 In SDK 22 `res` would be an error because the entry is archived. -//! // 👀 In SDK 23 `res` is Ok(123) because the entry is automatically restored. -//! assert!(res.is_err()); -//! } -//! } -//! -//! # fn main() { } -//! ``` -//! -//! The best way to address this change is to update the tests to explicitly -//! verify the expected entry TTL after the extension. This way there is no need -//! to rely on the storage behavior, and also the test becomes more robust as -//! it enforces the exact expected TTL value, so there is no risk of bumping -//! the ledger sequence further than the expected TTL and still having the test -//! pass. -//! -//! The example test above can be re-written as follows: -//! -//! ``` -//! #![no_std] -//! use soroban_sdk::{contract, contractimpl, contracttype, Env}; -//! -//! #[contract] -//! struct Contract; -//! -//! #[contracttype] -//! enum DataKey { -//! Key, -//! } -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn create_and_extend_entry(env: Env) { -//! env.storage().persistent().set(&DataKey::Key, &123_u32); -//! // Extend the entry to live for at least 1_000_000 ledgers. -//! env.storage() -//! .persistent() -//! .extend_ttl(&DataKey::Key, 1_000_000, 1_000_000); -//! } -//! -//! pub fn read_entry(env: Env) -> u32 { -//! env.storage().persistent().get(&DataKey::Key).unwrap() -//! } -//! } -//! -//! #[cfg(test)] -//! mod test { -//! extern crate std; -//! use soroban_sdk::testutils::{storage::Persistent, Ledger}; -//! -//! use super::*; -//! -//! #[test] -//! fn test_entry_ttl_extended() { -//! let env = Env::default(); -//! let contract = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract); -//! client.create_and_extend_entry(); -//! assert_eq!(client.read_entry(), 123); -//! -//! // 👀 Verify that the entry TTL was extended correctly by 1000000 ledgers. -//! env.as_contract(&contract, || { -//! assert_eq!(env.storage().persistent().get_ttl(&DataKey::Key), 1_000_000); -//! }); -//! } -//! -//! // 👀 This test is not really necessary, but it demonstrates the -//! // auto-restoration behavior in tests. -//! #[test] -//! fn test_auto_restore() { -//! let env = Env::default(); -//! let contract = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract); -//! client.create_and_extend_entry(); -//! let current_ledger = env.ledger().sequence(); -//! -//! // Bump ledger sequence past entry TTL. -//! env.ledger() -//! .set_sequence_number(current_ledger + 1_000_000 + 1); -//! // 👀 Entry can still be accessed because automatic restoration is emulated -//! // in tests. -//! assert_eq!(client.read_entry(), 123); -//! -//! // 👀 Automatic restoration is also accounted for in cost_estimate(): -//! let resources = env.cost_estimate().resources(); -//! // Even though `read_entry` call is normally read-only, auto-restoration -//! // will cause 2 entry writes here: 1 for the contract instance, another -//! // one for the restored entry. -//! assert_eq!(resources.write_entries, 2); -//! // 2 rent bumps will happen as well for the respective entries. -//! assert_eq!(resources.persistent_entry_rent_bumps, 2); -//! -//! // 👀 Entry TTL after auto-restoration can be observed via get_ttl(). -//! env.as_contract(&contract, || { -//! // Auto-restored entries have their TTL extended by the minimum -//! // possible TTL worth of ledgers (`min_persistent_entry_ttl`), -//! // including the ledger in which they were restored (that's why -//! // we subtract 1 here). -//! assert_eq!( -//! env.storage().persistent().get_ttl(&DataKey::Key), -//! env.ledger().get().min_persistent_entry_ttl - 1 -//! ); -//! }); -//! } -//! } -//! -//! # fn main() { } -//! ``` -//! diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs deleted file mode 100644 index 7e34326..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v23_contractevent.rs +++ /dev/null @@ -1,438 +0,0 @@ -//! [`contractevent`] replaces [`Events::publish`]. -//! -//! The [`contractevent`] macro provides a type-safe way to define and publish events, and -//! includes the event into the contract interface specification so that tooling, SDKs, and -//! generated clients can understand the events published. -//! -//! ## Example -//! -//! For example, consider the following event publishing code: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123u32; -//! # env.as_contract(&id, || { -//! // Define and publish the event: -//! env.events().publish( -//! // Event topics -//! (symbol_short!("increment"), &addr), -//! // Event data -//! Map::::from_array(&env, [ -//! (symbol_short!("count"), count.into()) -//! ]), -//! ); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("increment"), &addr).into_val(&env), -//! // Event data -//! Map::::from_array(&env, [ -//! (symbol_short!("count"), count.into()) -//! ]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! Replace it with the following code using [`contractevent`]: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123; -//! # env.as_contract(&id, || { -//! // Define the event: -//! #[contractevent] -//! pub struct Increment { -//! #[topic] -//! addr: Address, -//! count: u32, -//! } -//! -//! // Publish the event: -//! Increment { -//! addr: addr.clone(), -//! count: count, -//! }.publish(&env); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("increment"), &addr).into_val(&env), -//! // Event data -//! Map::::from_array(&env, [ -//! (symbol_short!("count"), count.into()) -//! ]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! ## Example: Vec Data -//! -//! By default the parameters not marked as `#[topic]`s are collected into a [`Map`] like in the -//! example above. If transitioning events that publish parameters in a [`Vec`], follow the -//! this example. -//! -//! Consider the following event publishing code: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Address, IntoVal, Vec, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123u32; -//! # env.as_contract(&id, || { -//! // Define and publish the event: -//! env.events().publish( -//! // Event topics -//! (symbol_short!("increment"), &addr), -//! // Event data -//! Vec::::from_array(&env, [count.into()]), -//! ); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("increment"), &addr).into_val(&env), -//! // Event data -//! Vec::::from_array(&env, [count.into()]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! Replace it with the following code using [`contractevent`]: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Vec, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123; -//! # env.as_contract(&id, || { -//! // Define the event: -//! #[contractevent(data_format = "vec")] -//! pub struct Increment { -//! #[topic] -//! addr: Address, -//! count: u32, -//! } -//! -//! // Publish the event: -//! Increment { -//! addr: addr.clone(), -//! count: count, -//! }.publish(&env); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("increment"), &addr).into_val(&env), -//! // Event data -//! Vec::::from_array(&env, [count.into()]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! ## Example: Other Data -//! -//! If transitioning events that publish some other type directly into the event's data field, -//! follow the this example. -//! -//! Consider the following event publishing code: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Address, IntoVal, Vec, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123u32; -//! # env.as_contract(&id, || { -//! // Define and publish the event: -//! env.events().publish( -//! // Event topics -//! (symbol_short!("increment"), &addr), -//! // Event data -//! count, -//! ); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("increment"), &addr).into_val(&env), -//! // Event data -//! count.into(), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! Replace it with the following code using [`contractevent`]: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123; -//! # env.as_contract(&id, || { -//! // Define the event: -//! #[contractevent(data_format = "single-value")] -//! pub struct Increment { -//! #[topic] -//! addr: Address, -//! count: u32, -//! } -//! -//! // Publish the event: -//! Increment { -//! addr: addr.clone(), -//! count: count, -//! }.publish(&env); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("increment"), &addr).into_val(&env), -//! // Event data -//! count.into(), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! ## Example: Customising Topics -//! -//! By default the topics of an event are made up of a single static topic that is the event's name -//! converted to snake_case, along with any dynamic topics specified by `#[topic]` on the field. -//! -//! ### Custom Static Topic -//! -//! The static topic can be changed using the `topics = [...]` option on [`contractevent`]: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123; -//! # env.as_contract(&id, || { -//! #[contractevent(topics = ["count_chn"])] -//! pub struct Increment { -//! #[topic] -//! addr: Address, -//! count: u32, -//! } -//! # -//! # Increment { -//! # addr: addr.clone(), -//! # count: count, -//! # }.publish(&env); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("count_chn"), &addr,).into_val(&env), -//! // Event data -//! Map::::from_array(&env, [ -//! (symbol_short!("count"), count.into()) -//! ]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! ### Multiple Static Topics -//! -//! Multiple static topics can be set using the `topics = [...]` option on [`contractevent`], with -//! up to two values: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123; -//! # env.as_contract(&id, || { -//! #[contractevent(topics = ["count", "increment"])] -//! pub struct Increment { -//! #[topic] -//! addr: Address, -//! count: u32, -//! } -//! # -//! # Increment { -//! # addr: addr.clone(), -//! # count: count, -//! # }.publish(&env); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (symbol_short!("count"), symbol_short!("increment"), &addr,).into_val(&env), -//! // Event data -//! Map::::from_array(&env, [ -//! (symbol_short!("count"), count.into()) -//! ]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! ### No Static Topics -//! -//! Zero static topics can be specified with the following configuration where `topics = []` is -//! provided to [`contractevent`]: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Map, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # let addr = Address::generate(&env); -//! # let count = 123; -//! # env.as_contract(&id, || { -//! #[contractevent(topics = [])] -//! pub struct Increment { -//! #[topic] -//! addr: Address, -//! count: u32, -//! } -//! # -//! # Increment { -//! # addr: addr.clone(), -//! # count: count, -//! # }.publish(&env); -//! # }); -//! -//! // Assert in tests on the published topics and data: -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! // Event topics -//! (&addr,).into_val(&env), -//! // Event data -//! Map::::from_array(&env, [ -//! (symbol_short!("count"), count.into()) -//! ]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! [`Events::publish`]: crate::events::Events::publish -//! [`Address`]: crate::MuxedAddress -//! [`MuxedAddress`]: crate::MuxedAddress -//! [`contractevent`]: crate::contractevent -//! [`Map`]: crate::Map diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs deleted file mode 100644 index 4fb7a3e..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_bn254.rs +++ /dev/null @@ -1,138 +0,0 @@ -//! BN254 (alt_bn128) elliptic curve support. -//! -//! Support for BN254 (also known as alt_bn128), a pairing-friendly elliptic curve commonly used in -//! zero-knowledge proof systems. -//! -//! The BN254 functionality is accessed via `env.crypto().bn254()`. -//! -//! ## New Types -//! -//! - [`Bn254G1Affine`] - A point in the G1 group (64 bytes, Ethereum-compatible format) -//! - [`Bn254G2Affine`] - A point in the G2 group (128 bytes, Ethereum-compatible format) -//! - [`Bn254Fr`] - A scalar field element (32 bytes, internally a `U256`) -//! - [`Bn254Fp`] - A base field element (32 bytes) -//! -//! ## New Operations -//! -//! - `g1_add` - Add two G1 points -//! - `g1_mul` - Multiply a G1 point by a scalar -//! - `pairing_check` - Multi-pairing check for ZK proof verification -//! -//! G1 points also support arithmetic operations via Rust traits: -//! - `Add` - Add two G1 points -//! - `Mul` - Multiply a G1 point by a scalar -//! - `Neg` - Negate a G1 point -//! -//! ## Example: Basic G1 Operations -//! -//! ``` -//! use soroban_sdk::{Env, BytesN, U256}; -//! use soroban_sdk::crypto::bn254::{Bn254Fr, Bn254G1Affine}; -//! -//! # fn main() { -//! let env = Env::default(); -//! let bn254 = env.crypto().bn254(); -//! -//! // The generator point G1 for BN254 -//! // G1 = (1, 2) -//! let g1_bytes: [u8; 64] = [ -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // x = 1 -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, // y = 2 -//! ]; -//! let g1 = Bn254G1Affine::from_array(&env, &g1_bytes); -//! -//! // Add the generator to itself: G + G = 2G -//! let g1_doubled = bn254.g1_add(&g1, &g1); -//! -//! // Or use the Add trait -//! let g1_doubled_alt = g1.clone() + g1.clone(); -//! assert_eq!(g1_doubled, g1_doubled_alt); -//! -//! // Scalar multiplication: 2 * G should equal G + G -//! let scalar: Bn254Fr = U256::from_u32(&env, 2).into(); -//! let g1_times_2 = bn254.g1_mul(&g1, &scalar); -//! assert_eq!(g1_doubled, g1_times_2); -//! -//! // Or use the Mul trait -//! let g1_times_2_alt = g1.clone() * scalar; -//! assert_eq!(g1_doubled, g1_times_2_alt); -//! # } -//! ``` -//! -//! ## Example: Point Negation -//! -//! ``` -//! use soroban_sdk::{Env, BytesN}; -//! use soroban_sdk::crypto::bn254::Bn254G1Affine; -//! -//! # fn main() { -//! let env = Env::default(); -//! let bn254 = env.crypto().bn254(); -//! -//! // G1 generator point (1, 2) -//! let g1_bytes: [u8; 64] = [ -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -//! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -//! ]; -//! let g1 = Bn254G1Affine::from_array(&env, &g1_bytes); -//! -//! // Negate the point: -G has same x but negated y -//! let neg_g1 = -g1.clone(); -//! -//! // G + (-G) = point at infinity (all zeros) -//! let sum = bn254.g1_add(&g1, &neg_g1); -//! let infinity = Bn254G1Affine::from_array(&env, &[0u8; 64]); -//! assert_eq!(sum, infinity); -//! # } -//! ``` -//! -//! ## Example: Pairing Check -//! -//! ``` -//! use soroban_sdk::{Env, vec, Vec}; -//! use soroban_sdk::crypto::bn254::{Bn254G1Affine, Bn254G2Affine}; -//! -//! # fn main() { -//! let env = Env::default(); -//! let bn254 = env.crypto().bn254(); -//! -//! // Example G1 and G2 points from Ethereum test vectors - https://github.com/ethereum/go-ethereum/blob/master/core/vm/testdata/precompiles/bn256Pairing.json -//! let g1_bytes: [u8; 64] = [ -//! 0x1c, 0x76, 0x47, 0x6f, 0x4d, 0xef, 0x4b, 0xb9, 0x45, 0x41, 0xd5, 0x7e, 0xbb, 0xa1, 0x19, 0x33, -//! 0x81, 0xff, 0xa7, 0xaa, 0x76, 0xad, 0xa6, 0x64, 0xdd, 0x31, 0xc1, 0x60, 0x24, 0xc4, 0x3f, 0x59, -//! 0x30, 0x34, 0xdd, 0x29, 0x20, 0xf6, 0x73, 0xe2, 0x04, 0xfe, 0xe2, 0x81, 0x1c, 0x67, 0x87, 0x45, -//! 0xfc, 0x81, 0x9b, 0x55, 0xd3, 0xe9, 0xd2, 0x94, 0xe4, 0x5c, 0x9b, 0x03, 0xa7, 0x6a, 0xef, 0x41, -//! ]; -//! let g1 = Bn254G1Affine::from_array(&env, &g1_bytes); -//! -//! let g2_bytes: [u8; 128] = [ -//! 0x20, 0x9d, 0xd1, 0x5e, 0xbf, 0xf5, 0xd4, 0x6c, 0x4b, 0xd8, 0x88, 0xe5, 0x1a, 0x93, 0xcf, 0x99, -//! 0xa7, 0x32, 0x96, 0x36, 0xc6, 0x35, 0x14, 0x39, 0x6b, 0x4a, 0x45, 0x20, 0x03, 0xa3, 0x5b, 0xf7, -//! 0x04, 0xbf, 0x11, 0xca, 0x01, 0x48, 0x3b, 0xfa, 0x8b, 0x34, 0xb4, 0x35, 0x61, 0x84, 0x8d, 0x28, -//! 0x90, 0x59, 0x60, 0x11, 0x4c, 0x8a, 0xc0, 0x40, 0x49, 0xaf, 0x4b, 0x63, 0x15, 0xa4, 0x16, 0x78, -//! 0x2b, 0xb8, 0x32, 0x4a, 0xf6, 0xcf, 0xc9, 0x35, 0x37, 0xa2, 0xad, 0x1a, 0x44, 0x5c, 0xfd, 0x0c, -//! 0xa2, 0xa7, 0x1a, 0xcd, 0x7a, 0xc4, 0x1f, 0xad, 0xbf, 0x93, 0x3c, 0x2a, 0x51, 0xbe, 0x34, 0x4d, -//! 0x12, 0x0a, 0x2a, 0x4c, 0xf3, 0x0c, 0x1b, 0xf9, 0x84, 0x5f, 0x20, 0xc6, 0xfe, 0x39, 0xe0, 0x7e, -//! 0xa2, 0xcc, 0xe6, 0x1f, 0x0c, 0x9b, 0xb0, 0x48, 0x16, 0x5f, 0xe5, 0xe4, 0xde, 0x87, 0x75, 0x50, -//! ]; -//! let g2 = Bn254G2Affine::from_array(&env, &g2_bytes); -//! -//! // Create vectors of G1 and G2 points -//! let g1_vec: Vec = vec![&env, g1]; -//! let g2_vec: Vec = vec![&env, g2]; -//! -//! // Perform pairing check -//! // Returns true if e(G1[0], G2[0]) * e(G1[1], G2[1]) * ... = 1 -//! let result = bn254.pairing_check(g1_vec, g2_vec); -//! // result will be true or false depending on the pairing equation -//! # } -//! ``` -//! -//! [`Bn254G1Affine`]: crate::crypto::bn254::Bn254G1Affine -//! [`Bn254G2Affine`]: crate::crypto::bn254::Bn254G2Affine -//! [`Bn254Fr`]: crate::crypto::bn254::Bn254Fr -//! [`Bn254Fp`]: crate::crypto::bn254::Bn254Fp diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs deleted file mode 100644 index 6be0777..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_contracttrait.rs +++ /dev/null @@ -1,335 +0,0 @@ -//! [`contracttrait`] macro for reusable contract interfaces. -//! -//! _Note: This feature was released in v23.4.0 but is being included in the migration notes for the -//! next major version, v25._ -//! -//! The [`contracttrait`] macro enables defining reusable contract interfaces as Rust traits with -//! default implementations. Contracts can implement these traits, and the default implementations -//! are automatically exported as contract functions. -//! -//! ## Generated Functionality -//! -//! When applied to a trait, [`contracttrait`] generates: -//! -//! - `{TraitName}Client` - A client for invoking the trait's functions on a contract -//! - `{TraitName}Args` - An enum of function arguments for the trait's functions -//! - `{TraitName}Spec` - The contract specification for the trait's functions -//! -//! These names can be customized using macro arguments (e.g., `client_name`, `args_name`, -//! `spec_name`). -//! -//! ## When to Use -//! -//! Use [`contracttrait`] when you want the trait to represent a contract interface. -//! -//! The [`contracttrait`] will make it possible to: -//! - Access a generated client for any contract implementing the interface. -//! - Automatically export default implementations that contracts can optionally override -//! - Share common functionality across contracts -//! -//! ## How It Works -//! -//! 1. **Define a trait** with [`contracttrait`] -//! -//! 2. **Implement the trait** with [`contractimpl`], including the `contracttrait` option: -//! `#[contractimpl(contracttrait)]` -//! -//! 3. **Override default functions as needed** - Contracts can provide their own implementations of -//! any function with default implementations. -//! -//! ## Patterns For Use -//! -//! Place traits that use [`contracttrait`] into a library crate, to share and make those traits -//! available to other crates and developers. -//! -//! [`contracttrait`]: crate::contracttrait -//! [`contractimpl`]: crate::contractimpl -//! -//! ## Example: Defining and Implementing a Trait -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; -//! -//! // A regular trait for admin access control - not exported as contract functions -//! pub trait RequireAuthForPause { -//! fn require_auth_for_pause(env: &Env); -//! } -//! -//! // Define a contracttrait with default implementations that require RequireAuthForPause -//! #[contracttrait] -//! pub trait Pausable: RequireAuthForPause { -//! fn is_paused(env: &Env) -> bool { -//! env.storage().instance().has(&"paused") -//! } -//! -//! fn pause(env: &Env) { -//! Self::require_auth_for_pause(env); -//! env.storage().instance().set(&"paused", &true); -//! } -//! -//! fn unpause(env: &Env) { -//! Self::require_auth_for_pause(env); -//! env.storage().instance().remove(&"paused"); -//! } -//! } -//! -//! #[contract] -//! pub struct MyContract; -//! -//! impl RequireAuthForPause for MyContract { -//! fn require_auth_for_pause(env: &Env) { -//! let admin: Address = env.storage().instance().get(&"admin").unwrap(); -//! admin.require_auth(); -//! } -//! } -//! -//! // Implement the trait - default functions are automatically exported -//! #[contractimpl(contracttrait)] -//! impl Pausable for MyContract {} -//! -//! #[contractimpl] -//! impl MyContract { -//! pub fn __constructor(env: &Env, admin: Address) { -//! env.storage().instance().set(&"admin", &admin); -//! } -//! -//! pub fn do_something(env: &Env) { -//! if Self::is_paused(env) { -//! panic!("contract is paused"); -//! } -//! // ... rest of the function -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! use soroban_sdk::{testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; -//! let env = Env::default(); -//! let admin = Address::generate(&env); -//! let contract_id = env.register(MyContract, (&admin,)); -//! let client = PausableClient::new(&env, &contract_id); -//! -//! assert!(!client.is_paused()); -//! client.mock_auths(&[MockAuth { -//! address: &admin, -//! invoke: &MockAuthInvoke { -//! contract: &contract_id, -//! fn_name: "pause", -//! args: ().into_val(&env), -//! sub_invokes: &[], -//! }, -//! }]).pause(); -//! assert!(client.is_paused()); -//! client.mock_auths(&[MockAuth { -//! address: &admin, -//! invoke: &MockAuthInvoke { -//! contract: &contract_id, -//! fn_name: "unpause", -//! args: ().into_val(&env), -//! sub_invokes: &[], -//! }, -//! }]).unpause(); -//! assert!(!client.is_paused()); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! ## Example: Overriding Default Implementations -//! -//! Contracts can override specific functions while keeping the defaults for others: -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; -//! -//! // A regular trait for admin access control - not exported as contract functions -//! pub trait RequireAuthForPause { -//! fn require_auth_for_pause(env: &Env); -//! } -//! -//! // Define a contracttrait with default implementations that require RequireAuthForPause -//! #[contracttrait] -//! pub trait Pausable: RequireAuthForPause { -//! fn is_paused(env: &Env) -> bool { -//! env.storage().instance().has(&"paused") -//! } -//! -//! fn pause(env: &Env) { -//! Self::require_auth_for_pause(env); -//! env.storage().instance().set(&"paused", &true); -//! } -//! -//! fn unpause(env: &Env) { -//! Self::require_auth_for_pause(env); -//! env.storage().instance().remove(&"paused"); -//! } -//! } -//! -//! #[contract] -//! pub struct MyContract; -//! -//! impl RequireAuthForPause for MyContract { -//! fn require_auth_for_pause(env: &Env) { -//! let admin: Address = env.storage().instance().get(&"admin").unwrap(); -//! admin.require_auth(); -//! } -//! } -//! -//! // Implement the trait - override default implementations as needed -//! #[contractimpl(contracttrait)] -//! impl Pausable for MyContract { -//! // Override is_paused with custom logic that returns false when not set -//! fn is_paused(env: &Env) -> bool { -//! env.storage().instance().get(&"paused").unwrap_or(false) -//! } -//! // pause() and unpause() use the default implementations -//! } -//! -//! #[contractimpl] -//! impl MyContract { -//! pub fn __constructor(env: &Env, admin: Address) { -//! env.storage().instance().set(&"admin", &admin); -//! } -//! -//! pub fn do_something(env: &Env) { -//! if Self::is_paused(env) { -//! panic!("contract is paused"); -//! } -//! // ... rest of the function -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! use soroban_sdk::{testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; -//! let env = Env::default(); -//! let admin = Address::generate(&env); -//! let contract_id = env.register(MyContract, (&admin,)); -//! let client = PausableClient::new(&env, &contract_id); -//! -//! assert!(!client.is_paused()); -//! client.mock_auths(&[MockAuth { -//! address: &admin, -//! invoke: &MockAuthInvoke { -//! contract: &contract_id, -//! fn_name: "pause", -//! args: ().into_val(&env), -//! sub_invokes: &[], -//! }, -//! }]).pause(); -//! assert!(client.is_paused()); -//! client.mock_auths(&[MockAuth { -//! address: &admin, -//! invoke: &MockAuthInvoke { -//! contract: &contract_id, -//! fn_name: "unpause", -//! args: ().into_val(&env), -//! sub_invokes: &[], -//! }, -//! }]).unpause(); -//! assert!(!client.is_paused()); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! ## Example: Using the Generated Client -//! -//! The generated `{TraitName}Client` can be used to call any contract that implements the trait: -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; -//! -//! // A regular trait for admin access control - not exported as contract functions -//! pub trait RequireAuthForPause { -//! fn require_auth_for_pause(env: &Env); -//! } -//! -//! // Define a contracttrait with default implementations that require RequireAuthForPause -//! #[contracttrait] -//! pub trait Pausable: RequireAuthForPause { -//! fn is_paused(env: &Env) -> bool { -//! env.storage().instance().has(&"paused") -//! } -//! -//! fn pause(env: &Env) { -//! Self::require_auth_for_pause(env); -//! env.storage().instance().set(&"paused", &true); -//! } -//! -//! fn unpause(env: &Env) { -//! Self::require_auth_for_pause(env); -//! env.storage().instance().remove(&"paused"); -//! } -//! } -//! -//! #[contract] -//! pub struct MyContract; -//! -//! impl RequireAuthForPause for MyContract { -//! fn require_auth_for_pause(env: &Env) { -//! let admin: Address = env.storage().instance().get(&"admin").unwrap(); -//! admin.require_auth(); -//! } -//! } -//! -//! // Implement the trait - default functions are automatically exported -//! #[contractimpl(contracttrait)] -//! impl Pausable for MyContract {} -//! -//! #[contractimpl] -//! impl MyContract { -//! pub fn __constructor(env: &Env, admin: Address) { -//! env.storage().instance().set(&"admin", &admin); -//! } -//! -//! pub fn do_something(env: &Env) { -//! if Self::is_paused(env) { -//! panic!("contract is paused"); -//! } -//! // ... rest of the function -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! use soroban_sdk::{testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; -//! let env = Env::default(); -//! let admin = Address::generate(&env); -//! let contract_id = env.register(MyContract, (&admin,)); -//! let client = PausableClient::new(&env, &contract_id); -//! -//! assert!(!client.is_paused()); -//! client.mock_auths(&[MockAuth { -//! address: &admin, -//! invoke: &MockAuthInvoke { -//! contract: &contract_id, -//! fn_name: "pause", -//! args: ().into_val(&env), -//! sub_invokes: &[], -//! }, -//! }]).pause(); -//! assert!(client.is_paused()); -//! client.mock_auths(&[MockAuth { -//! address: &admin, -//! invoke: &MockAuthInvoke { -//! contract: &contract_id, -//! fn_name: "unpause", -//! args: ().into_val(&env), -//! sub_invokes: &[], -//! }, -//! }]).unpause(); -//! assert!(!client.is_paused()); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs deleted file mode 100644 index 613cc04..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_event_testing.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! `Events::all()` return type changed from `Vec<(Address, Vec, Val)>` to [`ContractEvents`]. -//! -//! The [`ContractEvents`] struct provides a more ergonomic interface for asserting on -//! emitted events. It can be compared directly with: -//! - `[xdr::ContractEvent; _]` -//! - `std::vec::Vec` -//! - `Vec<(Address, Vec, Val)>` (maintains backward compatibility with the old format) -//! -//! The [`ContractEvents`] struct also provides utility methods: -//! - `filter_by_contract` - filter events by contract address -//! - `events` - get the underlying XDR events -//! -//! Additionally, events defined with [`contractevent`] now have a `to_xdr` method available with -//! `testutils` feature that converts the event to its XDR representation for comparison. -//! -//! ## Example: Using the old comparison style -//! -//! The old comparison style using `Vec<(Address, Vec, Val)>` still works: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Symbol, Val, testutils::{Address as _, Events as _}}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # env.as_contract(&id, || { -//! #[contractevent] -//! pub struct MyEvent { -//! #[topic] -//! name: Symbol, -//! value: u32, -//! } -//! -//! MyEvent { -//! name: symbol_short!("hello"), -//! value: 42, -//! }.publish(&env); -//! # }); -//! -//! // The old comparison style still works: -//! use soroban_sdk::Map; -//! assert_eq!( -//! env.events().all(), -//! vec![&env, -//! ( -//! id.clone(), -//! (symbol_short!("my_event"), symbol_short!("hello")).into_val(&env), -//! Map::::from_array(&env, [ -//! (symbol_short!("value"), 42u32.into()) -//! ]).into_val(&env), -//! ), -//! ] -//! ); -//! # } -//! ``` -//! -//! ## Example: Using XDR comparison (new recommended style) -//! -//! The new style uses `to_xdr` on the event for cleaner assertions: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Symbol, Val, testutils::{Address as _, Events as _}, Event}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let id = env.register(Contract, ()); -//! # -//! #[contractevent] -//! pub struct MyEvent { -//! #[topic] -//! name: Symbol, -//! value: u32, -//! } -//! -//! let event = MyEvent { -//! name: symbol_short!("hello"), -//! value: 42, -//! }; -//! -//! # env.as_contract(&id, || { -//! event.publish(&env); -//! # }); -//! -//! // New style: compare with XDR directly -//! assert_eq!( -//! env.events().all(), -//! std::vec![event.to_xdr(&env, &id)], -//! ); -//! # } -//! ``` -//! -//! ## Example: Filtering events by contract -//! -//! Use `filter_by_contract` to get events from a specific contract: -//! -//! ``` -//! # #![cfg(feature = "testutils")] -//! # use soroban_sdk::{contract, contractevent, contractimpl, symbol_short, vec, Env, Address, IntoVal, Symbol, Val, testutils::{Address as _, Events as _}, Event}; -//! # -//! # #[contract] -//! # pub struct Contract; -//! # -//! # fn main() { -//! # let env = Env::default(); -//! # let contract_a = env.register(Contract, ()); -//! # let contract_b = env.register(Contract, ()); -//! # -//! #[contractevent] -//! pub struct MyEvent { -//! #[topic] -//! name: Symbol, -//! value: u32, -//! } -//! -//! let event_a = MyEvent { -//! name: symbol_short!("hello"), -//! value: 1, -//! }; -//! let event_b = MyEvent { -//! name: symbol_short!("world"), -//! value: 2, -//! }; -//! -//! env.as_contract(&contract_a, || { -//! event_a.publish(&env); -//! env.as_contract(&contract_b, || { -//! event_b.publish(&env); -//! }); -//! }); -//! -//! // Filter to get only events from contract_a -//! assert_eq!( -//! env.events().all().filter_by_contract(&contract_a), -//! std::vec![event_a.to_xdr(&env, &contract_a)], -//! ); -//! -//! // Filter to get only events from contract_b -//! assert_eq!( -//! env.events().all().filter_by_contract(&contract_b), -//! std::vec![event_b.to_xdr(&env, &contract_b)], -//! ); -//! # } -//! ``` -//! -//! [`ContractEvents`]: crate::testutils::ContractEvents -//! [`contractevent`]: crate::contractevent diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs deleted file mode 100644 index d0a802c..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_poseidon.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! Poseidon and Poseidon2 permutation functions. -//! -//! Protocol 25 exposes low-level Poseidon and Poseidon2 permutation host functions -//! for advanced cryptographic use cases. These are available through the `CryptoHazmat` -//! interface under the `hazmat-crypto` feature. -//! -//! Higher level non-hazmat functionality will be released in a separate crate. -//! -//! ## ⚠️ Hazardous Materials Warning -//! -//! These are low-level cryptographic primitives. Most users should use higher-level -//! constructions built on top of these permutations. Incorrect usage can lead to -//! security vulnerabilities. -//! -//! ## Enabling the Feature -//! -//! Add the `hazmat-crypto` feature to your `Cargo.toml`: -//! -//! ```toml -//! [dependencies] -//! soroban-sdk = { version = "25", features = ["hazmat-crypto"] } -//! ``` -//! -//! ## Poseidon Permutation -//! -//! The `poseidon_permutation` function performs the standard Poseidon permutation -//! with a full MDS matrix. -//! -//! Parameters: -//! - `input` - State vector of `U256` field elements -//! - `field` - Field identifier (e.g., `"BN254"`) -//! - `t` - State width (number of elements) -//! - `d` - S-box exponent (typically 5) -//! - `rounds_f` - Number of full rounds (must be even) -//! - `rounds_p` - Number of partial rounds -//! - `mds` - MDS matrix (`t × t` matrix of `U256` elements) -//! - `round_constants` - Round constants (one vector per round) -//! -//! ## Poseidon2 Permutation -//! -//! The `poseidon2_permutation` function performs the Poseidon2 permutation with an -//! optimized internal matrix representation. -//! -//! Parameters: -//! - `input` - State vector of `U256` field elements -//! - `field` - Field identifier (e.g., `"BN254"`) -//! - `t` - State width (number of elements) -//! - `d` - S-box exponent (typically 5) -//! - `rounds_f` - Number of full rounds (must be even) -//! - `rounds_p` - Number of partial rounds -//! - `mat_internal_diag_m_1` - Diagonal of internal matrix minus identity -//! - `round_constants` - Round constants (one vector per round) -//! -//! ## Example -//! -//! ```ignore -//! use soroban_sdk::{bytesn, vec, Env, Symbol, U256}; -//! use soroban_sdk::crypto::CryptoHazmat; -//! -//! # fn main() { -//! let env = Env::default(); -//! -//! // Define MDS matrix (2x2 for t=2) -//! let mds = vec![ -//! &env, -//! vec![&env, -//! U256::from_be_bytes(&env, &bytesn!(&env, 0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5).into()), -//! U256::from_be_bytes(&env, &bytesn!(&env, 0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8).into()), -//! ], -//! vec![&env, -//! U256::from_be_bytes(&env, &bytesn!(&env, 0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9).into()), -//! U256::from_be_bytes(&env, &bytesn!(&env, 0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8).into()), -//! ], -//! ]; -//! -//! // Define round constants -//! let rc = vec![ -//! &env, -//! vec![&env, U256::from_u32(&env, 1), U256::from_u32(&env, 2)], -//! vec![&env, U256::from_u32(&env, 3), U256::from_u32(&env, 4)], -//! vec![&env, U256::from_u32(&env, 5), U256::from_u32(&env, 6)], -//! ]; -//! -//! let input = vec![&env, U256::from_u32(&env, 0), U256::from_u32(&env, 1)]; -//! -//! let hazmat = CryptoHazmat::new(&env); -//! let result = hazmat.poseidon_permutation( -//! &input, -//! Symbol::new(&env, "BN254"), -//! 2, // t: state width -//! 5, // d: s-box exponent -//! 2, // rounds_f: full rounds -//! 1, // rounds_p: partial rounds -//! &mds, -//! &rc, -//! ); -//! -//! assert_eq!(result.len(), 2); -//! # } -//! ``` diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs deleted file mode 100644 index fe3eda8..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating/v25_resource_limits.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! Resource limit enforcement in tests. -//! -//! ## Breaking Change: Tests May Fail Due to Resource Limits -//! -//! By default, [`Env::default()`] now enforces mainnet resource limits for contract invocations in -//! tests. **If your contract exceeds any resource limit, your tests will panic** with details -//! about which limits were exceeded. -//! -//! This provides an early warning that a contract might be too resource-heavy to run on mainnet. -//! -//! **If you see test failures after upgrading**, and you wish to test without mainnet limits -//! (e.g., while experimenting or optimizing), see [Disabling Resource -//! Limits](#disabling-resource-limits) below. -//! -//! ## New Default Behavior -//! -//! When creating a new `Env` with [`Env::default()`], mainnet resource limits are automatically -//! enforced. No changes to existing test code are required to benefit from this protection. -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, Env}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn execute() { -//! // ... code -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); // Mainnet limits enforced automatically -//! let contract_id = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract_id); -//! client.execute(); // Will panic if resource limit exceeded -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! ## Disabling Resource Limits -//! -//! For experimental contracts that are still being optimized, resource limit enforcement can be -//! disabled using [`CostEstimate::disable_resource_limits()`]: -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, Env}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn execute() { -//! // ... resource-heavy code -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! env.cost_estimate().disable_resource_limits(); // Disable resource limit -//! -//! let contract_id = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract_id); -//! client.execute(); // Won't panic even if limits exceeded -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! ## Custom Resource Limits -//! -//! Custom resource limits can be enforced using [`CostEstimate::enforce_resource_limits()`]: -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, Env}; -//! use soroban_sdk::testutils::cost_estimate::NetworkInvocationResourceLimits; -//! use soroban_env_host::InvocationResourceLimits; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn execute() { -//! // ... code -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! -//! // Use custom limits (this example uses mainnet limits as a base) -//! let mut limits = InvocationResourceLimits::mainnet(); -//! limits.instructions = 100_000_000; // Reduce instruction limit -//! env.cost_estimate().enforce_resource_limits(limits); -//! -//! let contract_id = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract_id); -//! client.execute(); // Uses the custom limits -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! ## Mainnet Resource Limits -//! -//! The [`NetworkInvocationResourceLimits`] trait provides the `mainnet()` method on -//! [`InvocationResourceLimits`] to get the current mainnet limits: -//! -//! - Instructions: 600,000,000 -//! - Memory: 41,943,040 bytes -//! - Disk read entries: 100 -//! - Write entries: 50 -//! - Ledger entries: 100 -//! - Disk read bytes: 200,000 -//! - Write bytes: 132,096 -//! - Contract events size: 16,384 bytes -//! - Max contract data key size: 250 bytes -//! - Max contract data entry size: 65,536 bytes -//! - Max contract code entry size: 131,072 bytes -//! -//! Note: These values are not pulled dynamically. The SDK will be updated from time-to-time to -//! pick up changes to mainnet limits. These changes may occur in any major, minor, or patch -//! release. -//! -//! [`Env::default()`]: crate::Env::default -//! [`CostEstimate::disable_resource_limits()`]: crate::testutils::cost_estimate::CostEstimate::disable_resource_limits -//! [`CostEstimate::enforce_resource_limits()`]: crate::testutils::cost_estimate::CostEstimate::enforce_resource_limits -//! [`InvocationResourceLimits`]: soroban_env_host::InvocationResourceLimits -//! [`NetworkInvocationResourceLimits`]: crate::testutils::cost_estimate::NetworkInvocationResourceLimits diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs deleted file mode 100644 index 1217947..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/crypto/bls12_381.rs +++ /dev/null @@ -1,1123 +0,0 @@ -#[cfg(not(target_family = "wasm"))] -use crate::xdr::ScVal; -use crate::{ - crypto::utils::BigInt, - env::internal::{self, BytesObject, U256Val, U64Val}, - unwrap::{UnwrapInfallible, UnwrapOptimized}, - Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, -}; -use core::{ - cmp::Ordering, - fmt::Debug, - ops::{Add, Mul, Neg, Sub}, -}; - -pub const FP_SERIALIZED_SIZE: usize = 48; // Size in bytes of a serialized Fp element in BLS12-381. The field modulus is 381 bits, requiring 48 bytes (384 bits) with 3 bits reserved for flags. -pub const FP2_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; -pub const G1_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; // Must match soroban_sdk_macro::map_type::G1_SERIALIZED_SIZE. -pub const G2_SERIALIZED_SIZE: usize = FP2_SERIALIZED_SIZE * 2; // Must match soroban_sdk_macro::map_type::G2_SERIALIZED_SIZE. - -/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381 -/// curve. -pub struct Bls12_381 { - env: Env, -} - -/// `Bls12381G1Affine` is a point in the G1 group (subgroup defined over the base field -/// `Fq`) of the BLS12-381 elliptic curve. -/// -/// This type is a thin wrapper around `BytesN<96>`. The [`from_bytes`](Self::from_bytes) -/// constructor does **not** validate the contents — it accepts any 96 bytes. -/// The serialization requirements below are enforced by the Soroban host when -/// the value is passed to a host function (e.g. `g1_add`, `g1_mul`, `pairing`). -/// Invalid bytes will cause the host call to trap, not construction. -/// -/// # Serialization: -/// - The 96 bytes represent the **uncompressed encoding** of a point in G1. The -/// Bytes consist of `be_byte(X) || be_byte(Y)` (`||` is concatenation), -/// where 'X' and 'Y' are the two coordinates, each being a base field element -/// `Fp` -/// - The most significant three bits (bits 0-3) of the first byte are reserved -/// for encoding flags: -/// - compression_flag (bit 0): Must always be unset (0), as only uncompressed -/// points are supported. -/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero -/// point), in which case all other bits must be zero. -/// - sort_flag (bit 2): Must always be unset (0). -/// -/// # Example Usage: -/// ```rust -/// use soroban_sdk::{Env, bytesn, crypto::bls12_381::{Bls12_381, Bls12381G1Affine}}; -/// let env = Env::default(); -/// let bls12_381 = env.crypto().bls12_381(); -/// let zero = Bls12381G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)); -/// let one = Bls12381G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1)); -/// let res = bls12_381.g1_add(&zero, &one); -/// assert_eq!(res, one); -/// ``` -#[derive(Clone)] -#[repr(transparent)] -pub struct Bls12381G1Affine(BytesN); - -/// Deprecated type alias for `Bls12381G1Affine`. -/// Use the fully-qualified `Bls12381G1Affine` to avoid ambiguity with BN254 types. -#[deprecated(note = "use `Bls12381G1Affine` instead")] -pub type G1Affine = Bls12381G1Affine; - -/// `Bls12381G2Affine` is a point in the G2 group (subgroup defined over the quadratic -/// extension field `Fq2`) of the BLS12-381 elliptic curve. -/// -/// This type is a thin wrapper around `BytesN<192>`. The [`from_bytes`](Self::from_bytes) -/// constructor does **not** validate the contents — it accepts any 192 bytes. -/// The serialization requirements below are enforced by the Soroban host when -/// the value is passed to a host function (e.g. `g2_add`, `g2_mul`, `pairing`). -/// Invalid bytes will cause the host call to trap, not construction. -/// -/// # Serialization: -/// - The 192 bytes represent the **uncompressed encoding** of a point in G2. -/// The bytes consist of `be_bytes(X_c1) || be_bytes(X_c0) || be_bytes(Y_c1) -/// || be_bytes(Y_c0)` (`||` is concatenation), where 'X' and 'Y' are the two -/// coordinates, each being an extension field element `Fp2` and `c0`, `c1` -/// are components of `Fp2` (each being `Fp`). -/// - The most significant three bits (bits 0-3) of the first byte are reserved -/// for encoding flags: -/// - compression_flag (bit 0): Must always be unset (0), as only uncompressed -/// points are supported. -/// - infinity_flag (bit 1): Set if the point is the point at infinity (zero -/// point), in which case all other bits must be zero. -/// - sort_flag (bit 2): Must always be unset (0). -#[derive(Clone)] -#[repr(transparent)] -pub struct Bls12381G2Affine(BytesN); - -/// Deprecated type alias for `Bls12381G2Affine`. -/// Use the fully-qualified `Bls12381G2Affine` to avoid ambiguity with BN254 types. -#[deprecated(note = "use `Bls12381G2Affine` instead")] -pub type G2Affine = Bls12381G2Affine; - -/// `Bls12381Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic -/// curve -/// -/// # Serialization: -/// - The 48 bytes represent the **big-endian encoding** of an element in the -/// field `Fp`. The value is serialized as a big-endian integer. -#[derive(Clone)] -#[repr(transparent)] -pub struct Bls12381Fp(BytesN); - -/// Deprecated type alias for `Bls12381Fp`. -/// Use the fully-qualified `Bls12381Fp` to avoid ambiguity with BN254 types. -#[deprecated(note = "use `Bls12381Fp` instead")] -pub type Fp = Bls12381Fp; - -/// `Bls12381Fp2` represents an element of the quadratic extension field `Fq2` of the -/// BLS12-381 elliptic curve -/// -/// # Serialization: -/// - The 96 bytes represent the **big-endian encoding** of an element in the -/// field `Fp2`. The bytes consist of `be_bytes(c1) || be_bytes(c0)` (`||` is -/// concatenation), where `c0` and `c1` are the two `Fp` elements (the real -/// and imaginary components). -#[derive(Clone)] -#[repr(transparent)] -pub struct Bls12381Fp2(BytesN); - -/// Deprecated type alias for `Bls12381Fp2`. -/// Use the fully-qualified `Bls12381Fp2` to avoid ambiguity with BN254 types. -#[deprecated(note = "use `Bls12381Fp2` instead")] -pub type Fp2 = Bls12381Fp2; - -/// `Bls12381Fr` represents an element in the BLS12-381 scalar field, which is a -/// prime field of order `r` (the order of the G1 and G2 groups). The struct is -/// internally represented with an `U256`, all arithmetic operations follow -/// modulo `r`. -#[derive(Clone)] -#[repr(transparent)] -pub struct Bls12381Fr(U256); - -/// Deprecated type alias for `Bls12381Fr`. -/// Use `Bls12381Fr` to avoid ambiguity with `Bn254Fr`. -#[deprecated(note = "use `Bls12381Fr` instead to avoid ambiguity with `Bn254Fr`")] -pub type Fr = Bls12381Fr; - -impl_bytesn_repr!(Bls12381G1Affine, G1_SERIALIZED_SIZE); -impl_bytesn_repr!(Bls12381G2Affine, G2_SERIALIZED_SIZE); -impl_bytesn_repr!(Bls12381Fp, FP_SERIALIZED_SIZE); -impl_bytesn_repr!(Bls12381Fp2, FP2_SERIALIZED_SIZE); - -// BLS12-381 base field modulus p in big-endian bytes. -// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab -const BLS12_381_FP_MODULUS_BE: [u8; FP_SERIALIZED_SIZE] = [ - 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, - 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, - 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, -]; - -fn validate_fp(bytes: &[u8; FP_SERIALIZED_SIZE]) { - if bytes >= &BLS12_381_FP_MODULUS_BE { - sdk_panic!("Bls12-381: Invalid Fp"); - } -} - -fn validate_fp2(bytes: &[u8; FP2_SERIALIZED_SIZE]) { - validate_fp(bytes[0..FP_SERIALIZED_SIZE].try_into().unwrap()); - validate_fp(bytes[FP_SERIALIZED_SIZE..].try_into().unwrap()); -} - -impl Bls12381G1Affine { - /// Wraps raw bytes as a G1 point without validation. - /// See [`Bls12381G1Affine`] for serialization requirements enforced by the host. - pub fn from_bytes(bytes: BytesN) -> Self { - Self(bytes) - } -} - -impl Bls12381G2Affine { - /// Wraps raw bytes as a G2 point without validation. - /// See [`Bls12381G2Affine`] for serialization requirements enforced by the host. - pub fn from_bytes(bytes: BytesN) -> Self { - Self(bytes) - } -} - -impl Bls12381Fp { - pub fn from_bytes(bytes: BytesN) -> Self { - validate_fp(&bytes.to_array()); - Self(bytes) - } -} - -impl Bls12381Fp2 { - pub fn from_bytes(bytes: BytesN) -> Self { - validate_fp2(&bytes.to_array()); - Self(bytes) - } -} - -impl Bls12381Fp { - pub fn env(&self) -> &Env { - self.0.env() - } - - // `Bls12381Fp` represents an element in the base field of the BLS12-381 elliptic curve. - // For an element a ∈ Fp, its negation `-a` is defined as: - // a + (-a) = 0 (mod p) - // where `p` is the field modulus, and to make a valid point coordinate on the - // curve, `a` also must be within the field range (i.e., 0 ≤ a < p). - fn checked_neg(&self) -> Option { - let fp_bigint: BigInt<6> = (&self.0).into(); - if fp_bigint.is_zero() { - return Some(self.clone()); - } - - // BLS12-381 base field modulus - const BLS12_381_MODULUS: [u64; 6] = [ - 13402431016077863595, - 2210141511517208575, - 7435674573564081700, - 7239337960414712511, - 5412103778470702295, - 1873798617647539866, - ]; - let mut res = BigInt(BLS12_381_MODULUS); - - // Compute modulus - value - let borrow = res.sub_with_borrow(&fp_bigint); - if borrow { - return None; - } - - let mut bytes = [0u8; FP_SERIALIZED_SIZE]; - res.copy_into_array(&mut bytes); - Some(Bls12381Fp::from_array(self.env(), &bytes)) - } - - /// Maps this `Bls12381Fp` element to a `Bls12381G1Affine` point using the [simplified SWU - /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0). - /// - ///
- ///
Warning
- /// The resulting point is on the curve but may not be in the prime-order subgroup (operations - /// like pairing may fail). To ensure the point is in the prime-order subgroup, cofactor - /// clearing must be performed on the output. - /// - /// For applications requiring a point directly in the prime-order subgroup, consider using - /// `hash_to_g1`, which handles subgroup checks and cofactor clearing internally. - ///
- pub fn map_to_g1(&self) -> Bls12381G1Affine { - self.env().crypto().bls12_381().map_fp_to_g1(self) - } -} - -impl From for BigInt<6> { - fn from(fp: Bls12381Fp) -> Self { - let inner: Bytes = fp.0.into(); - let mut limbs = [0u64; 6]; - for i in 0..6u32 { - let start = i * 8; - let mut slice = [0u8; 8]; - inner.slice(start..start + 8).copy_into_slice(&mut slice); - limbs[5 - i as usize] = u64::from_be_bytes(slice); - } - BigInt(limbs) - } -} - -impl Neg for &Bls12381Fp { - type Output = Bls12381Fp; - - fn neg(self) -> Self::Output { - match self.checked_neg() { - Some(v) => v, - None => sdk_panic!("invalid input - Bls12381Fp is larger than the field modulus"), - } - } -} - -impl Neg for Bls12381Fp { - type Output = Bls12381Fp; - - fn neg(self) -> Self::Output { - (&self).neg() - } -} - -impl Bls12381G1Affine { - pub fn env(&self) -> &Env { - self.0.env() - } - - pub fn is_in_subgroup(&self) -> bool { - self.env().crypto().bls12_381().g1_is_in_subgroup(self) - } - - pub fn checked_add(&self, rhs: &Self) -> Option { - self.env().crypto().bls12_381().g1_checked_add(self, rhs) - } -} - -impl Add for Bls12381G1Affine { - type Output = Bls12381G1Affine; - - fn add(self, rhs: Self) -> Self::Output { - self.env().crypto().bls12_381().g1_add(&self, &rhs) - } -} - -impl Mul for Bls12381G1Affine { - type Output = Bls12381G1Affine; - - fn mul(self, rhs: Bls12381Fr) -> Self::Output { - self.env().crypto().bls12_381().g1_mul(&self, &rhs) - } -} - -// Bls12381G1Affine represents a point (X, Y) on the BLS12-381 curve where X, Y ∈ Bls12381Fp -// Negation of (X, Y) is defined as (X, -Y) -impl Neg for &Bls12381G1Affine { - type Output = Bls12381G1Affine; - - fn neg(self) -> Self::Output { - let mut inner: Bytes = (&self.0).into(); - let y = Bls12381Fp::try_from_val( - inner.env(), - inner.slice(FP_SERIALIZED_SIZE as u32..).as_val(), - ) - .unwrap_optimized(); - let neg_y = -y; - inner.copy_from_slice(FP_SERIALIZED_SIZE as u32, &neg_y.to_array()); - Bls12381G1Affine::from_bytes( - BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(), - ) - } -} - -impl Neg for Bls12381G1Affine { - type Output = Bls12381G1Affine; - - fn neg(self) -> Self::Output { - (&self).neg() - } -} - -impl Bls12381Fp2 { - pub fn env(&self) -> &Env { - self.0.env() - } - - // An Bls12381Fp2 element is represented as c0 + c1 * X, where: - // - c0, c1 are base field elements (Bls12381Fp) - // - X is the quadratic non-residue used to construct the field extension - // The negation of c0 + c1 * X is (-c0) + (-c1) * X. - fn checked_neg(&self) -> Option { - let mut inner = self.to_array(); - let mut slice0 = [0; FP_SERIALIZED_SIZE]; - let mut slice1 = [0; FP_SERIALIZED_SIZE]; - slice0.copy_from_slice(&inner[0..FP_SERIALIZED_SIZE]); - slice1.copy_from_slice(&inner[FP_SERIALIZED_SIZE..FP2_SERIALIZED_SIZE]); - - // Convert both components to Bls12381Fp and negate them - let c0 = Bls12381Fp::from_array(self.env(), &slice0); - let c1 = Bls12381Fp::from_array(self.env(), &slice1); - - // If either component's negation fails, the whole operation fails - let neg_c0 = c0.checked_neg()?; - let neg_c1 = c1.checked_neg()?; - - // Reconstruct the Bls12381Fp2 element from negated components - inner[0..FP_SERIALIZED_SIZE].copy_from_slice(&neg_c0.to_array()); - inner[FP_SERIALIZED_SIZE..FP2_SERIALIZED_SIZE].copy_from_slice(&neg_c1.to_array()); - - Some(Bls12381Fp2::from_array(self.env(), &inner)) - } - - /// Maps this `Bls12381Fp2` element to a `Bls12381G2Affine` point using the [simplified SWU - /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0). - /// - ///
- ///
Warning
- /// The resulting point is on the curve but may not be in the prime-order subgroup (operations - /// like pairing may fail). To ensure the point is in the prime-order subgroup, cofactor - /// clearing must be performed on the output. - /// - /// For applications requiring a point directly in the prime-order subgroup, consider using - /// `hash_to_g2`, which handles subgroup checks and cofactor clearing internally. - ///
- pub fn map_to_g2(&self) -> Bls12381G2Affine { - self.env().crypto().bls12_381().map_fp2_to_g2(self) - } -} - -impl Neg for &Bls12381Fp2 { - type Output = Bls12381Fp2; - - fn neg(self) -> Self::Output { - match self.checked_neg() { - Some(v) => v, - None => { - sdk_panic!("invalid input - Bls12381Fp2 component is larger than the field modulus") - } - } - } -} - -impl Neg for Bls12381Fp2 { - type Output = Bls12381Fp2; - - fn neg(self) -> Self::Output { - (&self).neg() - } -} - -impl Bls12381G2Affine { - pub fn env(&self) -> &Env { - self.0.env() - } - - pub fn is_in_subgroup(&self) -> bool { - self.env().crypto().bls12_381().g2_is_in_subgroup(self) - } - - pub fn checked_add(&self, rhs: &Self) -> Option { - self.env().crypto().bls12_381().g2_checked_add(self, rhs) - } -} - -impl Add for Bls12381G2Affine { - type Output = Bls12381G2Affine; - - fn add(self, rhs: Self) -> Self::Output { - self.env().crypto().bls12_381().g2_add(&self, &rhs) - } -} - -impl Mul for Bls12381G2Affine { - type Output = Bls12381G2Affine; - - fn mul(self, rhs: Bls12381Fr) -> Self::Output { - self.env().crypto().bls12_381().g2_mul(&self, &rhs) - } -} - -// Bls12381G2Affine represents a point (X, Y) on the BLS12-381 quadratic extension curve where X, Y ∈ Bls12381Fp2 -// Negation of (X, Y) is defined as (X, -Y) -impl Neg for &Bls12381G2Affine { - type Output = Bls12381G2Affine; - - fn neg(self) -> Self::Output { - let mut inner: Bytes = (&self.0).into(); - let y = Bls12381Fp2::try_from_val( - inner.env(), - inner.slice(FP2_SERIALIZED_SIZE as u32..).as_val(), - ) - .unwrap_optimized(); - let neg_y = -y; - inner.copy_from_slice(FP2_SERIALIZED_SIZE as u32, &neg_y.to_array()); - Bls12381G2Affine::from_bytes( - BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(), - ) - } -} - -impl Neg for Bls12381G2Affine { - type Output = Bls12381G2Affine; - - fn neg(self) -> Self::Output { - (&self).neg() - } -} - -impl Bls12381Fr { - pub fn env(&self) -> &Env { - self.0.env() - } - - pub fn from_u256(value: U256) -> Self { - value.into() - } - - pub fn to_u256(&self) -> U256 { - self.0.clone() - } - - pub fn as_u256(&self) -> &U256 { - &self.0 - } - - pub fn from_bytes(bytes: BytesN<32>) -> Self { - U256::from_be_bytes(bytes.env(), bytes.as_ref()).into() - } - - pub fn to_bytes(&self) -> BytesN<32> { - self.as_u256().to_be_bytes().try_into().unwrap_optimized() - } - - pub fn as_val(&self) -> &Val { - self.0.as_val() - } - - pub fn to_val(&self) -> Val { - self.0.to_val() - } - - pub fn pow(&self, rhs: u64) -> Self { - self.env().crypto().bls12_381().fr_pow(self, rhs) - } - - pub fn inv(&self) -> Self { - self.env().crypto().bls12_381().fr_inv(self) - } -} - -// BLS12-381 scalar field modulus r in big-endian bytes. -// r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 -const BLS12_381_FR_MODULUS_BE: [u8; 32] = [ - 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05, - 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, -]; - -fn fr_modulus(env: &Env) -> U256 { - U256::from_be_bytes(env, &Bytes::from_array(env, &BLS12_381_FR_MODULUS_BE)) -} - -impl From for Bls12381Fr { - fn from(value: U256) -> Self { - // Keep all Fr construction paths canonical by reducing modulo r here. - // Constructors and deserialization paths should route through this impl. - // Skip the expensive rem_euclid when value is already canonical (< r), - // which is always the case for host-returned arithmetic results. - let modulus = fr_modulus(value.env()); - if value >= modulus { - Self(value.rem_euclid(&modulus)) - } else { - Self(value) - } - } -} - -impl From<&Bls12381Fr> for U256Val { - fn from(value: &Bls12381Fr) -> Self { - value.as_u256().into() - } -} - -impl TryFromVal for Bls12381Fr { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - let u = U256::try_from_val(env, val)?; - Ok(u.into()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, fr: &Bls12381Fr) -> Result { - Ok(fr.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, fr: &&Bls12381Fr) -> Result { - Ok(fr.to_val()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Bls12381Fr> for ScVal { - fn from(v: &Bls12381Fr) -> Self { - Self::from(&v.0) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for ScVal { - fn from(v: Bls12381Fr) -> Self { - (&v).into() - } -} - -impl Eq for Bls12381Fr {} - -impl PartialEq for Bls12381Fr { - fn eq(&self, other: &Self) -> bool { - self.as_u256().partial_cmp(other.as_u256()) == Some(Ordering::Equal) - } -} - -impl Debug for Bls12381Fr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Bls12381Fr({:?})", self.as_u256()) - } -} - -impl Add for Bls12381Fr { - type Output = Bls12381Fr; - - fn add(self, rhs: Self) -> Self::Output { - self.env().crypto().bls12_381().fr_add(&self, &rhs) - } -} - -impl Sub for Bls12381Fr { - type Output = Bls12381Fr; - - fn sub(self, rhs: Self) -> Self::Output { - self.env().crypto().bls12_381().fr_sub(&self, &rhs) - } -} - -impl Mul for Bls12381Fr { - type Output = Bls12381Fr; - - fn mul(self, rhs: Self) -> Self::Output { - self.env().crypto().bls12_381().fr_mul(&self, &rhs) - } -} - -impl Bls12_381 { - pub(crate) fn new(env: &Env) -> Bls12_381 { - Bls12_381 { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - // g1 - - /// Checks if a point `p` in G1 is in the correct subgroup. - pub fn g1_is_in_subgroup(&self, p: &Bls12381G1Affine) -> bool { - let env = self.env(); - let res = internal::Env::bls12_381_check_g1_is_in_subgroup(env, p.to_object()) - .unwrap_infallible(); - res.into() - } - - /// Checks if a G1 point is on the BLS12-381 curve (no subgroup check). - pub fn g1_is_on_curve(&self, point: &Bls12381G1Affine) -> bool { - let env = self.env(); - internal::Env::bls12_381_g1_is_on_curve(env, point.to_object()) - .unwrap_infallible() - .into() - } - - /// Adds two points `p0` and `p1` in G1. - pub fn g1_add(&self, p0: &Bls12381G1Affine, p1: &Bls12381G1Affine) -> Bls12381G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the - /// correct subgroup. Note the subgroup check is computationally expensive, - /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. + pn`, - /// it may make sense to only call g1_checked_add on the final addition, - /// while using `g1_add` (non-checked version) on the intermediate ones. - pub fn g1_checked_add( - &self, - p0: &Bls12381G1Affine, - p1: &Bls12381G1Affine, - ) -> Option { - let env = self.env(); - let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - let res = unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }; - let is_in_correct_subgroup: bool = - internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object()) - .unwrap_optimized() - .into(); - match is_in_correct_subgroup { - true => Some(res), - false => None, - } - } - - /// Multiplies a point `p0` in G1 by a scalar. - pub fn g1_mul(&self, p0: &Bls12381G1Affine, scalar: &Bls12381Fr) -> Bls12381G1Affine { - let env = self.env(); - let bin = - internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Performs a multi-scalar multiplication (MSM) operation in G1. - pub fn g1_msm(&self, vp: Vec, vs: Vec) -> Bls12381G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); - unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Maps an element in the base field `Bls12381Fp` to a point in G1. - pub fn map_fp_to_g1(&self, fp: &Bls12381Fp) -> Bls12381G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible(); - unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`. - pub fn hash_to_g1(&self, msg: &Bytes, dst: &Bytes) -> Bls12381G1Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object()) - .unwrap_infallible(); - unsafe { Bls12381G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - // g2 - - /// Checks if a point `p` in G2 is in the correct subgroup. - pub fn g2_is_in_subgroup(&self, p: &Bls12381G2Affine) -> bool { - let env = self.env(); - let res = internal::Env::bls12_381_check_g2_is_in_subgroup(env, p.to_object()) - .unwrap_infallible(); - res.into() - } - - /// Checks if a G2 point is on the BLS12-381 curve (no subgroup check). - pub fn g2_is_on_curve(&self, point: &Bls12381G2Affine) -> bool { - let env = self.env(); - internal::Env::bls12_381_g2_is_on_curve(env, point.to_object()) - .unwrap_infallible() - .into() - } - - /// Adds two points `p0` and `p1` in G2. - pub fn g2_add(&self, p0: &Bls12381G2Affine, p1: &Bls12381G2Affine) -> Bls12381G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the - /// correct subgroup. Note the subgroup check is computationally expensive, - /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. +pn`, - /// it may make sense to only call g2_checked_add on the final addition, - /// while using `g2_add` (non-checked version) on the intermediate ones. - pub fn g2_checked_add( - &self, - p0: &Bls12381G2Affine, - p1: &Bls12381G2Affine, - ) -> Option { - let env = self.env(); - let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object()) - .unwrap_infallible(); - let res = unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }; - let is_in_correct_subgroup: bool = - internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object()) - .unwrap_optimized() - .into(); - match is_in_correct_subgroup { - true => Some(res), - false => None, - } - } - - /// Multiplies a point `p0` in G2 by a scalar. - pub fn g2_mul(&self, p0: &Bls12381G2Affine, scalar: &Bls12381Fr) -> Bls12381G2Affine { - let env = self.env(); - let bin = - internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Performs a multi-scalar multiplication (MSM) operation in G2. - pub fn g2_msm(&self, vp: Vec, vs: Vec) -> Bls12381G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible(); - unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Maps an element in the base field `Bls12381Fp2` to a point in G2. - pub fn map_fp2_to_g2(&self, fp2: &Bls12381Fp2) -> Bls12381G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible(); - unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`. - pub fn hash_to_g2(&self, msg: &Bytes, dst: &Bytes) -> Bls12381G2Affine { - let env = self.env(); - let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object()) - .unwrap_infallible(); - unsafe { Bls12381G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - // pairing - - /// Performs a pairing check between vectors of points in G1 and G2. - /// - /// This function computes the pairing for each pair of points in the - /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if - /// the overall pairing result is equal to the identity in the target group. - /// - /// # Returns: - /// - `true` if the pairing check holds (i.e., the pairing result is valid - /// and equal to the identity element), otherwise `false`. - /// - /// # Panics: - /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. - pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { - let env = self.env(); - internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into()) - .unwrap_infallible() - .into() - } - - // scalar arithmetic - - /// Adds two scalars in the BLS12-381 scalar field `Bls12381Fr`. - pub fn fr_add(&self, lhs: &Bls12381Fr, rhs: &Bls12381Fr) -> Bls12381Fr { - let env = self.env(); - let v = internal::Env::bls12_381_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Subtracts one scalar from another in the BLS12-381 scalar field `Bls12381Fr`. - pub fn fr_sub(&self, lhs: &Bls12381Fr, rhs: &Bls12381Fr) -> Bls12381Fr { - let env = self.env(); - let v = internal::Env::bls12_381_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Multiplies two scalars in the BLS12-381 scalar field `Bls12381Fr`. - pub fn fr_mul(&self, lhs: &Bls12381Fr, rhs: &Bls12381Fr) -> Bls12381Fr { - let env = self.env(); - let v = internal::Env::bls12_381_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Raises a scalar to the power of a given exponent in the BLS12-381 scalar field `Bls12381Fr`. - pub fn fr_pow(&self, lhs: &Bls12381Fr, rhs: u64) -> Bls12381Fr { - let env = self.env(); - let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); - let v = internal::Env::bls12_381_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Computes the multiplicative inverse of a scalar in the BLS12-381 scalar field `Bls12381Fr`. - pub fn fr_inv(&self, lhs: &Bls12381Fr) -> Bls12381Fr { - let env = self.env(); - let v = internal::Env::bls12_381_fr_inv(env, lhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_g1affine_to_val() { - let env = Env::default(); - - let g1 = Bls12381G1Affine::from_bytes(BytesN::from_array(&env, &[1; 96])); - let val: Val = g1.clone().into_val(&env); - let rt: Bls12381G1Affine = val.into_val(&env); - - assert_eq!(g1, rt); - } - - #[test] - fn test_ref_g1affine_to_val() { - let env = Env::default(); - - let g1 = Bls12381G1Affine::from_bytes(BytesN::from_array(&env, &[1; 96])); - let val: Val = (&g1).into_val(&env); - let rt: Bls12381G1Affine = val.into_val(&env); - - assert_eq!(g1, rt); - } - - #[test] - fn test_doule_ref_g1affine_to_val() { - let env = Env::default(); - - let g1 = Bls12381G1Affine::from_bytes(BytesN::from_array(&env, &[1; 96])); - let val: Val = (&&g1).into_val(&env); - let rt: Bls12381G1Affine = val.into_val(&env); - - assert_eq!(g1, rt); - } - - #[test] - fn test_fr_to_val() { - let env = Env::default(); - - let fr = Bls12381Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); - let val: Val = fr.clone().into_val(&env); - let rt: Bls12381Fr = val.into_val(&env); - - assert_eq!(fr, rt); - } - - #[test] - fn test_ref_fr_to_val() { - let env = Env::default(); - - let fr = Bls12381Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); - let val: Val = (&fr).into_val(&env); - let rt: Bls12381Fr = val.into_val(&env); - - assert_eq!(fr, rt); - } - - #[test] - fn test_double_ref_fr_to_val() { - let env = Env::default(); - - let fr = Bls12381Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); - let val: Val = (&&fr).into_val(&env); - let rt: Bls12381Fr = val.into_val(&env); - - assert_eq!(fr, rt); - } - - #[test] - fn test_fr_eq_both_unreduced() { - let env = Env::default(); - let r = fr_modulus(&env); - let one = U256::from_u32(&env, 1); - - let a = Bls12381Fr::from_u256(r.add(&one)); - let b = Bls12381Fr::from_u256(one.clone()); - assert_eq!(a, b); - - let two_r_plus_one = r.add(&r).add(&one); - let c = Bls12381Fr::from_u256(two_r_plus_one); - assert_eq!(a, c); - assert_eq!(b, c); - } - - #[test] - fn test_fr_eq_unreduced_vs_zero() { - let env = Env::default(); - let r = fr_modulus(&env); - let zero = U256::from_u32(&env, 0); - - let a = Bls12381Fr::from_u256(r); - let b = Bls12381Fr::from_u256(zero); - assert_eq!(a, b); - } - - #[test] - fn test_fr_reduced_value_unchanged() { - let env = Env::default(); - let r = fr_modulus(&env); - let val = r.sub(&U256::from_u32(&env, 1)); - - let fr = Bls12381Fr::from_u256(val.clone()); - assert_eq!(fr.to_u256(), val); - - let fr42 = Bls12381Fr::from_u256(U256::from_u32(&env, 42)); - assert_eq!(fr42.to_u256(), U256::from_u32(&env, 42)); - } - - #[test] - fn test_fr_from_bytes_reduces() { - let env = Env::default(); - let one_fr = Bls12381Fr::from_u256(U256::from_u32(&env, 1)); - - // BLS12-381 r+1 as big-endian bytes - let fr_from_bytes = Bls12381Fr::from_bytes(bytesn!( - &env, - 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000002 - )); - assert_eq!(fr_from_bytes, one_fr); - } - - #[test] - fn test_fr_try_from_val_reduces() { - let env = Env::default(); - let r = fr_modulus(&env); - let one = U256::from_u32(&env, 1); - - let unreduced_u256 = r.add(&one); - let val: Val = unreduced_u256.into_val(&env); - let fr_from_val: Bls12381Fr = val.into_val(&env); - let fr_one = Bls12381Fr::from_u256(one); - assert_eq!(fr_from_val, fr_one); - } - - #[test] - fn test_fr_u256_into_reduces() { - // Direct From::from / .into() path must reduce - let env = Env::default(); - let r = fr_modulus(&env); - let one = U256::from_u32(&env, 1); - - let fr: Bls12381Fr = r.add(&one).into(); // r+1 via .into() - let fr_one: Bls12381Fr = one.into(); - assert_eq!(fr, fr_one); - } - - #[test] - fn test_fr_eq_unreduced_vs_host_computed() { - // User-provided unreduced Fr vs host-computed Fr - let env = Env::default(); - let bls = Bls12_381::new(&env); - let r = fr_modulus(&env); - let five = U256::from_u32(&env, 5); - - // User provides r+5 (unreduced) - let user_fr = Bls12381Fr::from_u256(r.add(&five)); - // Host computes 2+3 = 5 (always reduced) - let host_fr = bls.fr_add( - &Bls12381Fr::from_u256(U256::from_u32(&env, 2)), - &Bls12381Fr::from_u256(U256::from_u32(&env, 3)), - ); - assert_eq!(user_fr, host_fr); - } - - // Fp validation tests - - #[test] - fn test_fp_max_valid_accepted() { - let env = Env::default(); - // p - 1 (last byte 0xaa instead of 0xab) - let mut p_minus_1 = BLS12_381_FP_MODULUS_BE; - p_minus_1[FP_SERIALIZED_SIZE - 1] -= 1; - let _ = Bls12381Fp::from_array(&env, &p_minus_1); - } - - #[test] - #[should_panic(expected = "Bls12-381: Invalid Fp")] - fn test_fp_at_modulus_panics() { - let env = Env::default(); - let _ = Bls12381Fp::from_array(&env, &BLS12_381_FP_MODULUS_BE); - } - - #[test] - #[should_panic(expected = "Bls12-381: Invalid Fp")] - fn test_fp_above_modulus_panics() { - let env = Env::default(); - let mut above = BLS12_381_FP_MODULUS_BE; - above[FP_SERIALIZED_SIZE - 1] += 1; // p + 1 - let _ = Bls12381Fp::from_array(&env, &above); - } - - #[test] - fn test_fp_from_bytes_validates() { - let env = Env::default(); - // Zero should be valid - let _ = Bls12381Fp::from_bytes(BytesN::from_array(&env, &[0u8; FP_SERIALIZED_SIZE])); - } - - #[test] - #[should_panic(expected = "Bls12-381: Invalid Fp")] - fn test_fp_from_bytes_rejects_modulus() { - let env = Env::default(); - let _ = Bls12381Fp::from_bytes(BytesN::from_array(&env, &BLS12_381_FP_MODULUS_BE)); - } - - #[test] - #[should_panic(expected = "Bls12-381: Invalid Fp")] - fn test_fp_try_from_val_rejects_modulus() { - let env = Env::default(); - let bytes = BytesN::from_array(&env, &BLS12_381_FP_MODULUS_BE); - let val: Val = bytes.into_val(&env); - let _: Bls12381Fp = val.into_val(&env); - } - - #[test] - #[should_panic(expected = "Bls12-381: Invalid Fp")] - fn test_fp2_component_above_modulus_panics() { - let env = Env::default(); - // First Fp component is the modulus (invalid), second is zero (valid) - let mut fp2_bytes = [0u8; FP2_SERIALIZED_SIZE]; - fp2_bytes[0..FP_SERIALIZED_SIZE].copy_from_slice(&BLS12_381_FP_MODULUS_BE); - let _ = Bls12381Fp2::from_array(&env, &fp2_bytes); - } - - #[test] - #[should_panic(expected = "Bls12-381: Invalid Fp")] - fn test_fp2_second_component_above_modulus_panics() { - let env = Env::default(); - // First Fp component is zero (valid), second is the modulus (invalid) - let mut fp2_bytes = [0u8; FP2_SERIALIZED_SIZE]; - fp2_bytes[FP_SERIALIZED_SIZE..].copy_from_slice(&BLS12_381_FP_MODULUS_BE); - let _ = Bls12381Fp2::from_array(&env, &fp2_bytes); - } - - #[test] - fn test_fp2_max_valid_accepted() { - let env = Env::default(); - // Both components are p-1 (valid) - let mut p_minus_1 = BLS12_381_FP_MODULUS_BE; - p_minus_1[FP_SERIALIZED_SIZE - 1] -= 1; - let mut fp2_bytes = [0u8; FP2_SERIALIZED_SIZE]; - fp2_bytes[0..FP_SERIALIZED_SIZE].copy_from_slice(&p_minus_1); - fp2_bytes[FP_SERIALIZED_SIZE..].copy_from_slice(&p_minus_1); - let _ = Bls12381Fp2::from_array(&env, &fp2_bytes); - } - - #[test] - fn test_bls12_381_fp_modulus_matches_arkworks() { - use ark_bls12_381::Fq; - use ark_ff::{BigInteger, PrimeField}; - - let be_bytes = Fq::MODULUS.to_bytes_be(); - assert_eq!( - be_bytes.as_slice(), - &BLS12_381_FP_MODULUS_BE, - "BLS12-381 Fp modulus does not match arkworks" - ); - } - - #[test] - fn test_bls12_381_fr_modulus_matches_arkworks() { - use ark_bls12_381::Fr as ArkFr; - use ark_ff::{BigInteger, PrimeField}; - - let be_bytes = ArkFr::MODULUS.to_bytes_be(); - assert_eq!( - be_bytes.as_slice(), - &BLS12_381_FR_MODULUS_BE, - "BLS12-381 Fr modulus does not match arkworks" - ); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs deleted file mode 100644 index 6185700..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/crypto/bn254.rs +++ /dev/null @@ -1,727 +0,0 @@ -#[cfg(not(target_family = "wasm"))] -use crate::xdr::ScVal; -use crate::{ - crypto::utils::BigInt, - env::internal::{self, BytesObject, U256Val, U64Val}, - unwrap::{UnwrapInfallible, UnwrapOptimized}, - Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256, -}; -use core::{ - cmp::Ordering, - fmt::Debug, - ops::{Add, Mul, Neg, Sub}, -}; - -pub const BN254_FP_SERIALIZED_SIZE: usize = 32; // Size in bytes of a serialized Bn254Fp element in BN254. The field modulus is 254 bits, requiring 32 bytes (256 bits). -pub const BN254_G1_SERIALIZED_SIZE: usize = BN254_FP_SERIALIZED_SIZE * 2; // Size in bytes of a serialized G1 element in BN254. Each coordinate (X, Y) is 32 bytes. -pub const BN254_G2_SERIALIZED_SIZE: usize = BN254_G1_SERIALIZED_SIZE * 2; // Size in bytes of a serialized G2 element in BN254. Each coordinate (X, Y) is 64 bytes (2 Bn254Fp elements per coordinate). - -/// Bn254 provides access to curve and pairing operations on the BN254 -/// (also known as alt_bn128) curve. -pub struct Bn254 { - env: Env, -} - -/// `Bn254G1Affine` is a point in the G1 group (subgroup defined over the base field -/// `Fq` with prime order `q = -/// 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47`) of the -/// BN254 elliptic curve. -/// -/// This type is a thin wrapper around `BytesN<64>`. The [`from_bytes`](Self::from_bytes) -/// constructor does **not** validate the contents — it accepts any 64 bytes. -/// The serialization requirements below are enforced by the Soroban host when -/// the value is passed to a host function (e.g. `g1_add`, `g1_mul`, `pairing`). -/// Invalid bytes will cause the host call to trap, not construction. -/// -/// # Serialization (Ethereum-compatible format): -/// - The 64 bytes represent the **uncompressed encoding** of a point in G1 -/// - Format: `be_bytes(X) || be_bytes(Y)` where `||` denotes concatenation -/// - X and Y are curve coordinates, each a 32-byte big-endian Bn254Fp field element -/// - The two flag bits (bits 0x80 and 0x40 of the first byte) must be unset -/// - The point at infinity is encoded as 64 zero bytes -/// - Points must be on the curve (no subgroup check required for G1) -#[derive(Clone)] -#[repr(transparent)] -pub struct Bn254G1Affine(BytesN); - -/// `Bn254G2Affine` is a point in the G2 group (subgroup defined over the quadratic -/// extension field `Fq2`) of the BN254 elliptic curve. -/// -/// This type is a thin wrapper around `BytesN<128>`. The [`from_bytes`](Self::from_bytes) -/// constructor does **not** validate the contents — it accepts any 128 bytes. -/// The serialization requirements below are enforced by the Soroban host when -/// the value is passed to a host function (e.g. `g2_add`, `g2_mul`, `pairing`). -/// Invalid bytes will cause the host call to trap, not construction. -/// -/// # Serialization (Ethereum-compatible format): -/// - The 128 bytes represent the **uncompressed encoding** of a point in G2 -/// - Format: `be_bytes(X) || be_bytes(Y)` where each coordinate is an Fp2 -/// element (64 bytes) - Fp2 element encoding: `be_bytes(c1) || be_bytes(c0)` -/// where: -/// - c0 is the real component (32-byte big-endian Bn254Fp element) -/// - c1 is the imaginary component (32-byte big-endian Bn254Fp element) -/// - The two flag bits (bits 0x80 and 0x40 of the first byte) must be unset -/// - The point at infinity is encoded as 128 zero bytes -/// - Points must be on the curve AND in the correct subgroup -#[derive(Clone)] -#[repr(transparent)] -pub struct Bn254G2Affine(BytesN); - -/// `Bn254Fr` represents an element in the BN254 scalar field, which is a prime -/// field of order `r = -/// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001`. The -/// struct is internally represented with a `U256`, all arithmetic operations -/// follow modulo `r`. -#[derive(Clone)] -#[repr(transparent)] -pub struct Bn254Fr(U256); - -/// Deprecated type alias for `Bn254Fr`. -/// Use `Bn254Fr` to avoid ambiguity with `Bls12381Fr`. -#[deprecated(note = "use `Bn254Fr` instead to avoid ambiguity with `Bls12381Fr`")] -pub type Fr = Bn254Fr; - -/// `Bn254Fp` represents an element of the base field `Bn254Fp` of the BN254 elliptic curve -/// -/// # Serialization: -/// - The 32 bytes represent the **big-endian encoding** of an element in the -/// field `Bn254Fp`. The value is serialized as a big-endian integer. -#[derive(Clone)] -#[repr(transparent)] -pub struct Bn254Fp(BytesN); - -impl_bytesn_repr!(Bn254G1Affine, BN254_G1_SERIALIZED_SIZE); -impl_bytesn_repr!(Bn254G2Affine, BN254_G2_SERIALIZED_SIZE); -impl_bytesn_repr!(Bn254Fp, BN254_FP_SERIALIZED_SIZE); - -// BN254 base field modulus p in big-endian bytes. -// p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 -const BN254_FP_MODULUS_BE: [u8; BN254_FP_SERIALIZED_SIZE] = [ - 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, 0x58, 0x5d, - 0x97, 0x81, 0x6a, 0x91, 0x68, 0x71, 0xca, 0x8d, 0x3c, 0x20, 0x8c, 0x16, 0xd8, 0x7c, 0xfd, 0x47, -]; - -fn validate_bn254_fp(bytes: &[u8; BN254_FP_SERIALIZED_SIZE]) { - if bytes >= &BN254_FP_MODULUS_BE { - sdk_panic!("Bn254: Invalid Fp"); - } -} - -impl Bn254G1Affine { - /// Wraps raw bytes as a G1 point without validation. - /// See [`Bn254G1Affine`] for serialization requirements enforced by the host. - pub fn from_bytes(bytes: BytesN) -> Self { - Self(bytes) - } -} - -impl Bn254G2Affine { - /// Wraps raw bytes as a G2 point without validation. - /// See [`Bn254G2Affine`] for serialization requirements enforced by the host. - pub fn from_bytes(bytes: BytesN) -> Self { - Self(bytes) - } -} - -impl Bn254Fp { - pub fn from_bytes(bytes: BytesN) -> Self { - validate_bn254_fp(&bytes.to_array()); - Self(bytes) - } -} - -impl Bn254G1Affine { - pub fn env(&self) -> &Env { - self.0.env() - } -} - -impl Bn254Fp { - pub fn env(&self) -> &Env { - self.0.env() - } - - // `Bn254Fp` represents an element in the base field of the BN254 elliptic curve. - // For an element a ∈ Bn254Fp, its negation `-a` is defined as: - // a + (-a) = 0 (mod p) - // where `p` is the field modulus, and to make a valid point coordinate on the - // curve, `a` also must be within the field range (i.e., 0 ≤ a < p). - fn checked_neg(&self) -> Option { - let fq_bigint: BigInt<4> = (&self.0).into(); - if fq_bigint.is_zero() { - return Some(self.clone()); - } - - //BN254 base field modulus - const BN254_MODULUS: [u64; 4] = [ - 4332616871279656263, - 10917124144477883021, - 13281191951274694749, - 3486998266802970665, - ]; - let mut res = BigInt(BN254_MODULUS); - - // Compute modulus - value - let borrow = res.sub_with_borrow(&fq_bigint); - if borrow { - return None; - } - - let mut bytes = [0u8; BN254_FP_SERIALIZED_SIZE]; - res.copy_into_array(&mut bytes); - Some(Bn254Fp::from_array(self.env(), &bytes)) - } -} - -impl Neg for &Bn254Fp { - type Output = Bn254Fp; - - fn neg(self) -> Self::Output { - match self.checked_neg() { - Some(v) => v, - None => sdk_panic!("invalid input - Bn254Fp is larger than the field modulus"), - } - } -} - -impl Neg for Bn254Fp { - type Output = Bn254Fp; - - fn neg(self) -> Self::Output { - (&self).neg() - } -} - -impl Add for Bn254G1Affine { - type Output = Bn254G1Affine; - - fn add(self, rhs: Self) -> Self::Output { - self.env().crypto().bn254().g1_add(&self, &rhs) - } -} - -impl Mul for Bn254G1Affine { - type Output = Bn254G1Affine; - - fn mul(self, rhs: Bn254Fr) -> Self::Output { - self.env().crypto().bn254().g1_mul(&self, &rhs) - } -} - -// Bn254G1Affine represents a point (X, Y) on the BN254 curve where X, Y ∈ Bn254Fp -// Negation of (X, Y) is defined as (X, -Y) -impl Neg for &Bn254G1Affine { - type Output = Bn254G1Affine; - - fn neg(self) -> Self::Output { - let mut inner: Bytes = (&self.0).into(); - let y = Bn254Fp::try_from_val( - inner.env(), - inner.slice(BN254_FP_SERIALIZED_SIZE as u32..).as_val(), - ) - .unwrap_optimized(); - let neg_y = -y; - inner.copy_from_slice(BN254_FP_SERIALIZED_SIZE as u32, &neg_y.to_array()); - Bn254G1Affine::from_bytes( - BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(), - ) - } -} - -impl Neg for Bn254G1Affine { - type Output = Bn254G1Affine; - - fn neg(self) -> Self::Output { - (&self).neg() - } -} - -impl Bn254G2Affine { - pub fn env(&self) -> &Env { - self.0.env() - } -} - -impl Bn254Fr { - pub fn env(&self) -> &Env { - self.0.env() - } - - pub fn from_u256(value: U256) -> Self { - value.into() - } - - pub fn to_u256(&self) -> U256 { - self.0.clone() - } - - pub fn as_u256(&self) -> &U256 { - &self.0 - } - - pub fn from_bytes(bytes: BytesN<32>) -> Self { - U256::from_be_bytes(bytes.env(), bytes.as_ref()).into() - } - - pub fn to_bytes(&self) -> BytesN<32> { - self.as_u256().to_be_bytes().try_into().unwrap_optimized() - } - - pub fn as_val(&self) -> &Val { - self.0.as_val() - } - - pub fn to_val(&self) -> Val { - self.0.to_val() - } - - pub fn pow(&self, rhs: u64) -> Self { - self.env().crypto().bn254().fr_pow(self, rhs) - } - - pub fn inv(&self) -> Self { - self.env().crypto().bn254().fr_inv(self) - } -} - -impl Add for Bn254Fr { - type Output = Bn254Fr; - - fn add(self, rhs: Self) -> Self::Output { - self.env().crypto().bn254().fr_add(&self, &rhs) - } -} - -impl Sub for Bn254Fr { - type Output = Bn254Fr; - - fn sub(self, rhs: Self) -> Self::Output { - self.env().crypto().bn254().fr_sub(&self, &rhs) - } -} - -impl Mul for Bn254Fr { - type Output = Bn254Fr; - - fn mul(self, rhs: Self) -> Self::Output { - self.env().crypto().bn254().fr_mul(&self, &rhs) - } -} - -// BN254 scalar field modulus r in big-endian bytes. -// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 -const BN254_FR_MODULUS_BE: [u8; 32] = [ - 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, 0x58, 0x5d, - 0x28, 0x33, 0xe8, 0x48, 0x79, 0xb9, 0x70, 0x91, 0x43, 0xe1, 0xf5, 0x93, 0xf0, 0x00, 0x00, 0x01, -]; - -fn fr_modulus(env: &Env) -> U256 { - U256::from_be_bytes(env, &Bytes::from_array(env, &BN254_FR_MODULUS_BE)) -} - -impl From for Bn254Fr { - fn from(value: U256) -> Self { - // Keep all Bn254Fr construction paths canonical by reducing modulo r here. - // Constructors and deserialization paths should route through this impl. - // Skip the expensive rem_euclid when value is already canonical (< r), - // which is always the case for host-returned arithmetic results. - let modulus = fr_modulus(value.env()); - if value >= modulus { - Self(value.rem_euclid(&modulus)) - } else { - Self(value) - } - } -} - -impl From<&Bn254Fr> for U256Val { - fn from(value: &Bn254Fr) -> Self { - value.as_u256().into() - } -} - -impl TryFromVal for Bn254Fr { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - let u = U256::try_from_val(env, val)?; - Ok(u.into()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, fr: &Bn254Fr) -> Result { - Ok(fr.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, fr: &&Bn254Fr) -> Result { - Ok(fr.to_val()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Bn254Fr> for ScVal { - fn from(v: &Bn254Fr) -> Self { - Self::from(&v.0) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for ScVal { - fn from(v: Bn254Fr) -> Self { - (&v).into() - } -} - -impl Eq for Bn254Fr {} - -impl PartialEq for Bn254Fr { - fn eq(&self, other: &Self) -> bool { - self.as_u256().partial_cmp(other.as_u256()) == Some(core::cmp::Ordering::Equal) - } -} - -impl Debug for Bn254Fr { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Bn254Fr({:?})", self.as_u256()) - } -} - -impl Bn254 { - pub(crate) fn new(env: &Env) -> Bn254 { - Bn254 { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - /// Adds two points `p0` and `p1` in G1. - pub fn g1_add(&self, p0: &Bn254G1Affine, p1: &Bn254G1Affine) -> Bn254G1Affine { - let env = self.env(); - let bin = - internal::Env::bn254_g1_add(env, p0.to_object(), p1.to_object()).unwrap_infallible(); - unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Multiplies a point `p0` in G1 by a scalar. - pub fn g1_mul(&self, p0: &Bn254G1Affine, scalar: &Bn254Fr) -> Bn254G1Affine { - let env = self.env(); - let bin = - internal::Env::bn254_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible(); - unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - // pairing - - /// Performs a multi-pairing check between vectors of points in G1 and G2. - /// - /// This function computes the pairing for each pair of points in the - /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if - /// the product of all pairings is equal to 1 in the target group Bn254Fp. - /// - /// # Returns: - /// - `true` if the pairing check holds (i.e., the product of pairings equals 1), - /// otherwise `false`. - /// - /// # Panics: - /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty. - pub fn pairing_check(&self, vp1: Vec, vp2: Vec) -> bool { - let env = self.env(); - internal::Env::bn254_multi_pairing_check(env, vp1.into(), vp2.into()) - .unwrap_infallible() - .into() - } - - /// Performs a multi-scalar multiplication (MSM) operation in G1. - pub fn g1_msm(&self, vp: Vec, vs: Vec) -> Bn254G1Affine { - let env = self.env(); - let bin = internal::Env::bn254_g1_msm(env, vp.into(), vs.into()).unwrap_infallible(); - unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Checks if a G1 point is on the BN254 curve. - pub fn g1_is_on_curve(&self, point: &Bn254G1Affine) -> bool { - let env = self.env(); - internal::Env::bn254_g1_is_on_curve(env, point.to_object()) - .unwrap_infallible() - .into() - } - - // scalar arithmetic - - /// Adds two scalars in the BN254 scalar field `Bn254Fr`. - pub fn fr_add(&self, lhs: &Bn254Fr, rhs: &Bn254Fr) -> Bn254Fr { - let env = self.env(); - let v = internal::Env::bn254_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Subtracts one scalar from another in the BN254 scalar field `Bn254Fr`. - pub fn fr_sub(&self, lhs: &Bn254Fr, rhs: &Bn254Fr) -> Bn254Fr { - let env = self.env(); - let v = internal::Env::bn254_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Multiplies two scalars in the BN254 scalar field `Bn254Fr`. - pub fn fr_mul(&self, lhs: &Bn254Fr, rhs: &Bn254Fr) -> Bn254Fr { - let env = self.env(); - let v = internal::Env::bn254_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Raises a scalar to the power of a given exponent in the BN254 scalar field `Bn254Fr`. - pub fn fr_pow(&self, lhs: &Bn254Fr, rhs: u64) -> Bn254Fr { - let env = self.env(); - let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized(); - let v = internal::Env::bn254_fr_pow(env, lhs.into(), rhs).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } - - /// Computes the multiplicative inverse of a scalar in the BN254 scalar field `Bn254Fr`. - pub fn fr_inv(&self, lhs: &Bn254Fr) -> Bn254Fr { - let env = self.env(); - let v = internal::Env::bn254_fr_inv(env, lhs.into()).unwrap_infallible(); - U256::try_from_val(env, &v).unwrap_infallible().into() - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_g1affine_to_val() { - let env = Env::default(); - - let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64])); - let val: Val = g1.clone().into_val(&env); - let rt: Bn254G1Affine = val.into_val(&env); - - assert_eq!(g1, rt); - } - - #[test] - fn test_ref_g1affine_to_val() { - let env = Env::default(); - - let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64])); - let val: Val = (&g1).into_val(&env); - let rt: Bn254G1Affine = val.into_val(&env); - - assert_eq!(g1, rt); - } - - #[test] - fn test_double_ref_g1affine_to_val() { - let env = Env::default(); - - let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64])); - let val: Val = (&&g1).into_val(&env); - let rt: Bn254G1Affine = val.into_val(&env); - - assert_eq!(g1, rt); - } - - #[test] - fn test_fr_to_val() { - let env = Env::default(); - - let fr = Bn254Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); - let val: Val = fr.clone().into_val(&env); - let rt: Bn254Fr = val.into_val(&env); - - assert_eq!(fr, rt); - } - - #[test] - fn test_ref_fr_to_val() { - let env = Env::default(); - - let fr = Bn254Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); - let val: Val = (&fr).into_val(&env); - let rt: Bn254Fr = val.into_val(&env); - - assert_eq!(fr, rt); - } - - #[test] - fn test_double_ref_fr_to_val() { - let env = Env::default(); - - let fr = Bn254Fr::from_bytes(BytesN::from_array(&env, &[1; 32])); - let val: Val = (&&fr).into_val(&env); - let rt: Bn254Fr = val.into_val(&env); - - assert_eq!(fr, rt); - } - - #[test] - fn test_fr_eq_both_unreduced() { - // Both inputs are user-provided unreduced values representing the same field element - let env = Env::default(); - let r = fr_modulus(&env); - let one = U256::from_u32(&env, 1); - - let a = Bn254Fr::from_u256(r.add(&one)); // r+1 ≡ 1 (mod r) - let b = Bn254Fr::from_u256(one.clone()); // 1 - assert_eq!(a, b); - - // Both unreduced by different multiples of r - let two_r_plus_one = r.add(&r).add(&one); - let c = Bn254Fr::from_u256(two_r_plus_one); // 2r+1 ≡ 1 (mod r) - assert_eq!(a, c); - assert_eq!(b, c); - } - - #[test] - fn test_fr_eq_unreduced_vs_zero() { - // value == r should reduce to 0 - let env = Env::default(); - let r = fr_modulus(&env); - let zero = U256::from_u32(&env, 0); - - let a = Bn254Fr::from_u256(r); - let b = Bn254Fr::from_u256(zero); - assert_eq!(a, b); - } - - #[test] - fn test_fr_reduced_value_unchanged() { - // value < r should be preserved as-is - let env = Env::default(); - let r = fr_modulus(&env); - let val = r.sub(&U256::from_u32(&env, 1)); // r-1 - - let fr = Bn254Fr::from_u256(val.clone()); - assert_eq!(fr.to_u256(), val); - - // small values - let fr42 = Bn254Fr::from_u256(U256::from_u32(&env, 42)); - assert_eq!(fr42.to_u256(), U256::from_u32(&env, 42)); - } - - #[test] - fn test_fr_from_bytes_reduces() { - // from_bytes should also reduce since it goes through From - let env = Env::default(); - let one_fr = Bn254Fr::from_u256(U256::from_u32(&env, 1)); - - // BN254 r+1 as big-endian bytes - let fr_from_bytes = Bn254Fr::from_bytes(bytesn!( - &env, - 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000002 - )); - assert_eq!(fr_from_bytes, one_fr); - } - - #[test] - fn test_fr_try_from_val_reduces() { - // TryFromVal path must also reduce - let env = Env::default(); - let r = fr_modulus(&env); - let one = U256::from_u32(&env, 1); - - // Create an unreduced U256 value (r+1), convert to Val, then to Fr - let unreduced_u256 = r.add(&one); - let val: Val = unreduced_u256.into_val(&env); - let fr_from_val: Bn254Fr = val.into_val(&env); - let fr_one = Bn254Fr::from_u256(one); - assert_eq!(fr_from_val, fr_one); - } - - #[test] - fn test_fr_u256_into_reduces() { - // Direct From::from / .into() path must reduce - let env = Env::default(); - let r = fr_modulus(&env); - let one = U256::from_u32(&env, 1); - - let fr: Bn254Fr = r.add(&one).into(); // r+1 via .into() - let fr_one: Bn254Fr = one.into(); - assert_eq!(fr, fr_one); - } - - // Bn254Fp validation tests - - #[test] - fn test_bn254_fp_max_valid_accepted() { - let env = Env::default(); - // p - 1 (last byte 0x46 instead of 0x47) - let mut p_minus_1 = BN254_FP_MODULUS_BE; - p_minus_1[BN254_FP_SERIALIZED_SIZE - 1] -= 1; - let _ = Bn254Fp::from_array(&env, &p_minus_1); - } - - #[test] - #[should_panic(expected = "Bn254: Invalid Fp")] - fn test_bn254_fp_at_modulus_panics() { - let env = Env::default(); - let _ = Bn254Fp::from_array(&env, &BN254_FP_MODULUS_BE); - } - - #[test] - #[should_panic(expected = "Bn254: Invalid Fp")] - fn test_bn254_fp_above_modulus_panics() { - let env = Env::default(); - let mut above = BN254_FP_MODULUS_BE; - above[BN254_FP_SERIALIZED_SIZE - 1] += 1; // p + 1 - let _ = Bn254Fp::from_array(&env, &above); - } - - #[test] - fn test_bn254_fp_from_bytes_validates() { - let env = Env::default(); - // Zero should be valid - let _ = Bn254Fp::from_bytes(BytesN::from_array(&env, &[0u8; BN254_FP_SERIALIZED_SIZE])); - } - - #[test] - #[should_panic(expected = "Bn254: Invalid Fp")] - fn test_bn254_fp_from_bytes_rejects_modulus() { - let env = Env::default(); - let _ = Bn254Fp::from_bytes(BytesN::from_array(&env, &BN254_FP_MODULUS_BE)); - } - - #[test] - #[should_panic(expected = "Bn254: Invalid Fp")] - fn test_bn254_fp_try_from_val_rejects_modulus() { - let env = Env::default(); - let bytes = BytesN::from_array(&env, &BN254_FP_MODULUS_BE); - let val: Val = bytes.into_val(&env); - let _: Bn254Fp = val.into_val(&env); - } - - #[test] - fn test_bn254_fp_modulus_matches_arkworks() { - use ark_bn254::Fq; - use ark_ff::{BigInteger, PrimeField}; - - let be_bytes = Fq::MODULUS.to_bytes_be(); - assert_eq!( - be_bytes.as_slice(), - &BN254_FP_MODULUS_BE, - "BN254 Fp modulus does not match arkworks" - ); - } - - #[test] - fn test_bn254_fr_modulus_matches_arkworks() { - use ark_bn254::Fr as ArkFr; - use ark_ff::{BigInteger, PrimeField}; - - let be_bytes = ArkFr::MODULUS.to_bytes_be(); - assert_eq!( - be_bytes.as_slice(), - &BN254_FR_MODULUS_BE, - "BN254 Fr modulus does not match arkworks" - ); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs deleted file mode 100644 index fe19ee1..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/crypto/utils.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::BytesN; - -// This routine was copied with slight modification from the arkworks library: -// https://github.com/arkworks-rs/algebra/blob/bf1c9b22b30325ef4df4f701dedcb6dea904c587/ff/src/biginteger/arithmetic.rs#L66-L79 -// Copyright 2022 arkworks contributors. arkworks zkSNARK ecosystem [Computer software]. https://github.com/arkworks-rs/ -// Licensed under the Apache License, Version 2.0 -fn sbb_for_sub_with_borrow(a: &mut u64, b: u64, borrow: u8) -> u8 { - let tmp = (1u128 << 64) + u128::from(*a) - u128::from(b) - u128::from(borrow); - // casting is safe here because `tmp` can only exceed u64 by a single - // (borrow) bit, which we capture in the next line. - *a = tmp as u64; - u8::from(tmp >> 64 == 0) -} - -#[derive(Debug)] -pub(crate) struct BigInt(pub [u64; N]); - -impl BigInt { - pub fn sub_with_borrow(&mut self, other: &Self) -> bool { - let mut borrow = 0; - for i in 0..N { - borrow = sbb_for_sub_with_borrow(&mut self.0[i], other.0[i], borrow); - } - borrow != 0 - } - - pub fn copy_into_array(&self, slice: &mut [u8; M]) { - const { - if M != N * 8 { - panic!("BigInt::copy_into_array with mismatched array length") - } - } - - for i in 0..N { - let limb_bytes = self.0[N - 1 - i].to_be_bytes(); - slice[i * 8..(i + 1) * 8].copy_from_slice(&limb_bytes); - } - } - - pub fn is_zero(&self) -> bool { - self.0 == [0; N] - } -} - -impl From<&BytesN> for BigInt { - fn from(bytes: &BytesN) -> Self { - const { - if M != N * 8 { - panic!("BytesN::Into - length mismatch") - } - } - - let array = bytes.to_array(); - let mut limbs = [0u64; N]; - for i in 0..N { - let start = i * 8; - let end = start + 8; - let mut chunk = [0u8; 8]; - chunk.copy_from_slice(&array[start..end]); - limbs[N - 1 - i] = u64::from_be_bytes(chunk); - } - BigInt(limbs) - } -} From 52da975a4ae3494a844acd148056f1ef1c7f5de6 Mon Sep 17 00:00:00 2001 From: Qoder-Undefined Date: Thu, 23 Jul 2026 17:02:31 +0100 Subject: [PATCH 4/4] fixesss --- temp_sdk/soroban-sdk-26.0.1/src/_features.rs | 141 -- temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs | 324 --- temp_sdk/soroban-sdk-26.0.1/src/address.rs | 450 ---- .../soroban-sdk-26.0.1/src/address_payload.rs | 126 - .../src/alloc/bump_pointer.rs | 122 - temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs | 61 - .../soroban-sdk-26.0.1/src/arbitrary_extra.rs | 71 - temp_sdk/soroban-sdk-26.0.1/src/auth.rs | 108 - temp_sdk/soroban-sdk-26.0.1/src/bytes.rs | 1839 -------------- .../src/constructor_args.rs | 32 - temp_sdk/soroban-sdk-26.0.1/src/crypto.rs | 396 --- temp_sdk/soroban-sdk-26.0.1/src/deploy.rs | 469 ---- temp_sdk/soroban-sdk-26.0.1/src/env.rs | 2240 ----------------- temp_sdk/soroban-sdk-26.0.1/src/error.rs | 37 - temp_sdk/soroban-sdk-26.0.1/src/events.rs | 162 -- .../src/into_val_for_contract_fn.rs | 46 - temp_sdk/soroban-sdk-26.0.1/src/iter.rs | 87 - temp_sdk/soroban-sdk-26.0.1/src/ledger.rs | 184 -- temp_sdk/soroban-sdk-26.0.1/src/lib.rs | 1255 --------- temp_sdk/soroban-sdk-26.0.1/src/logs.rs | 170 -- temp_sdk/soroban-sdk-26.0.1/src/map.rs | 1169 --------- .../soroban-sdk-26.0.1/src/muxed_address.rs | 416 --- temp_sdk/soroban-sdk-26.0.1/src/num.rs | 1123 --------- temp_sdk/soroban-sdk-26.0.1/src/prng.rs | 586 ----- .../soroban-sdk-26.0.1/src/spec_shaking.rs | 433 ---- temp_sdk/soroban-sdk-26.0.1/src/storage.rs | 775 ------ temp_sdk/soroban-sdk-26.0.1/src/string.rs | 417 --- temp_sdk/soroban-sdk-26.0.1/src/symbol.rs | 299 --- temp_sdk/soroban-sdk-26.0.1/src/tests.rs | 55 - temp_sdk/soroban-sdk-26.0.1/src/testutils.rs | 798 ------ temp_sdk/soroban-sdk-26.0.1/src/token.rs | 491 ---- .../src/try_from_val_for_contract_fn.rs | 58 - temp_sdk/soroban-sdk-26.0.1/src/tuple.rs | 73 - temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs | 96 - temp_sdk/soroban-sdk-26.0.1/src/vec.rs | 2000 --------------- temp_sdk/soroban-sdk-26.0.1/src/xdr.rs | 118 - 36 files changed, 17227 deletions(-) delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_features.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/address.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/auth.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/bytes.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/crypto.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/deploy.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/env.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/error.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/events.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/iter.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/ledger.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/lib.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/logs.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/map.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/num.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/prng.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/storage.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/string.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/symbol.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/tests.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/testutils.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/token.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/tuple.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/vec.rs delete mode 100644 temp_sdk/soroban-sdk-26.0.1/src/xdr.rs diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_features.rs b/temp_sdk/soroban-sdk-26.0.1/src/_features.rs deleted file mode 100644 index f009d51..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_features.rs +++ /dev/null @@ -1,141 +0,0 @@ -//! # Features -//! -//! The SDK provides several Cargo features that enable additional functionality. -//! -//! ## `testutils` -//! -//! Enables test utilities for writing tests that interact with contracts. -//! Required for using [`Env::default()`] in tests, generating test addresses, -//! and other test helpers. Only available for non-Wasm targets. -//! -//! ## `alloc` -//! -//! Enables the [`alloc`][crate::alloc] module, providing access to the global -//! allocator for use in contracts. -//! -//! ## `hazmat-crypto` -//! -//! Exposes low-level cryptographic primitives (e.g. -//! [`CryptoHazmat`][crate::crypto::CryptoHazmat]) that are easy to misuse. -//! Use with care. -//! -//! ## `hazmat-address` -//! -//! Exposes low-level address primitives (e.g. -//! [`Address::to_payload`][crate::Address::to_payload], -//! [`Address::from_payload`][crate::Address::from_payload]) that are easy to -//! misuse. Use with care. -//! -//! ## `experimental_spec_shaking_v2` -//! -//! Enables v2 spec shaking, an improved mechanism for controlling which type, -//! event, and function definitions appear in a contract's spec. -//! -//! ### Spec Shaking v1 (default, no feature flag) -//! -//! - Lib imports (via `contractimport!`): exported -//! - Wasm imports (via `contractimport!`): not exported -//! - `pub` types: exported -//! - Non-`pub` types: not exported -//! - All events: exported -//! - All functions: exported -//! -//! ### Spec Shaking v2 (this feature) -//! -//! - Everything exported (types, events, functions, imports) -//! - Unused entries shaken out using dead code / spec elimination -//! -//! A contract's spec (the `contractspecv0` custom section in the Wasm binary) -//! contains entries for every function, type, and event defined by the contract. -//! When types or events are defined but not actually used at a contract boundary -//! (parameters, return values, error returns, or event publishes), their spec -//! entries are dead weight. Spec shaking removes them. -//! -//! ### How It Works -//! -//! When this feature is enabled, the SDK embeds 14-byte **markers** in the Wasm -//! data section for each exported type and event. A marker consists of a -//! `SpEcV1` magic prefix followed by 8 bytes of a SHA-256 hash of the spec -//! entry's XDR. -//! -//! Markers are placed inside functions that are only called when the type is -//! actually used: -//! - **Function parameters**: marker is triggered when deserializing the input. -//! - **Function return values**: marker is triggered when serializing the output. -//! - **Error returns**: marker is triggered via `Result` serialization. -//! - **Event publishes**: marker is triggered inside the `publish()` call. -//! - **Nested types**: a type's marker function calls the marker functions of -//! its field types, so nested types are transitively marked. -//! - **Container types**: `Vec`, `Map`, `Option`, and `Result` -//! propagate markers to their inner types. -//! -//! The Rust compiler's dead code elimination (DCE) removes markers for types -//! that are never used, while keeping markers for types that are. -//! -//! Post-build tools (e.g. `stellar-cli`) scan the Wasm data section for -//! `SpEcV1` markers, match them against spec entries, and strip any entries -//! without a corresponding marker. -//! -//! ### Changed Behaviour -//! -//! When this feature is enabled the following macros change behaviour: -//! -//! #### [`contracttype`] -//! -//! Without this feature, spec entries are only generated for `pub` types (or -//! when `export = true` is explicitly set). With this feature, spec entries -//! and markers are generated for all types regardless of visibility, unless -//! `export = false` is explicitly set. This ensures all types can participate -//! in spec shaking. -//! -//! #### [`contracterror`] -//! -//! Same as [`contracttype`]: without this feature, spec entries are only -//! generated for `pub` types. With this feature, spec entries and markers are -//! generated for all error enums regardless of visibility, unless -//! `export = false` is explicitly set. -//! -//! #### [`contractevent`] -//! -//! Markers are embedded for all events, allowing post-build tools to strip -//! spec entries for events that are never published at a contract boundary. -//! -//! #### [`contractimport!`] -//! -//! Without this feature, [`contractimport!`] generates imported types with -//! `export = false`. Imported types do not produce spec entries in the -//! importing contract's spec. They are purely local Rust types used for -//! serialization. The importing contract's spec only contains its own function -//! definitions, and callers must look at the imported contract's spec to find -//! the type definitions. -//! -//! With this feature, [`contractimport!`] generates imported types with -//! `export = true`. Imported types produce spec entries and markers in the -//! importing contract, just like locally defined types. This changes the -//! contract's spec to be self-contained — it includes the type definitions for -//! all types used at the contract boundary, regardless of where those types -//! were originally defined. Specifically: -//! -//! - Imported types that are used in the contract's function signatures or -//! events will have their markers survive DCE and their spec entries will be -//! kept after shaking. -//! - Imported types that are **not** used at any contract boundary will have -//! their markers eliminated by DCE and their spec entries will be stripped. -//! -//! This ensures that a contract importing a large interface only includes spec -//! entries for the types it actually uses, while still producing a -//! self-contained spec. -//! -//! ### Build Requirements -//! -//! This feature requires building with `stellar contract build` from -//! `stellar-cli` v25.2.0 or newer. Building a contract for wasm (e.g. with -//! `cargo build --target wasm32v1-none`) will produce a build error unless the -//! `SOROBAN_SDK_BUILD_SYSTEM_SUPPORTS_SPEC_SHAKING_V2` environment variable is -//! set. The check only fires for wasm targets; native builds (e.g. unit tests) -//! are unaffected. -//! -//! [`contracttype`]: crate::contracttype -//! [`contracterror`]: crate::contracterror -//! [`contractevent`]: crate::contractevent -//! [`contractimport!`]: crate::contractimport diff --git a/temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs b/temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs deleted file mode 100644 index bb3bb2c..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/_migrating.rs +++ /dev/null @@ -1,324 +0,0 @@ -//! # Migrating from v25 to v26 -//! -//! 1. Add support for [CAP-78: Host functions for performing limited TTL extensions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0078.md). -//! New `extend_ttl_with_limits` methods on [`Persistent`], [`Instance`], and -//! [`Deployer`] provide bounded control over TTL extensions with `min_extension` and -//! `max_extension` parameters. -//! -//! 2. Add support for [CAP-82: Checked 256-bit integer arithmetic host functions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0082.md). -//! New `checked_*` methods on [`U256`] and [`I256`] (`checked_add`, `checked_sub`, -//! `checked_mul`, `checked_div`, `checked_pow`, `checked_rem_euclid`, `checked_shl`, -//! `checked_shr`) return `Option` instead of panicking on overflow. Also adds -//! `min_value` and `max_value` methods on [`U256`] and [`I256`] to fetch the -//! value bounds of each type. -//! -//! 3. Add support for [CAP-80: Host functions for efficient ZK BN254 use cases](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0080.md). -//! [`BN254`] gains scalar field arithmetic (`Fr` `Add`/`Sub`/`Mul` traits, `pow`, `inv`), -//! multi-scalar multiplication (`g1_msm`), and curve validation (`g1_is_on_curve`). -//! [`BLS12381`] gains `g1_is_on_curve` and `g2_is_on_curve`. -//! -//! 4. Add support for [CAP-79: Host functions for muxed address strkey conversions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0079.md). -//! New method [`MuxedAddress::to_strkey`] converts muxed addresses to Stellar strkey format. -//! -//! 5. Add support for [CAP-73: Allow SAC to create G-account balances](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0073.md). -//! Update the [`StellarAssetInterface`] to include the new method [`StellarAssetInterface::trust`]. This method creates -//! an unlimited trustline for the contract's asset, if applicable. -//! -//! [`Persistent`]: crate::storage::Persistent -//! [`Instance`]: crate::storage::Instance -//! [`Deployer`]: crate::deploy::Deployer -//! [`U256`]: crate::U256 -//! [`I256`]: crate::I256 -//! [`MuxedAddress::to_strkey`]: crate::MuxedAddress::to_strkey -//! [`StellarAssetInterface`]: crate::token::StellarAssetInterface -//! [`StellarAssetInterface::trust`]: crate::token::StellarAssetInterface::trust -//! [`BN254`]: crate::crypto::bn254 -//! [`BLS12381`]: crate::crypto::bls12_381 -//! -//! # Migrating from v23 to v25 -//! -//! 1. [`Events::all()` return type changed from `Vec<(Address, Vec, Val)>` to `ContractEvents`][v25_event_testing]. -//! The new type supports the old comparison format, so most code will continue to work. -//! New methods like `filter_by_contract()` and XDR comparison via `to_xdr()` are now available. -//! -//! 2. [BN254 (alt_bn128) elliptic curve support added][v25_bn254]. -//! Access via `env.crypto().bn254()` for G1/G2 point operations and pairing checks. -//! -//! 3. [Poseidon and Poseidon2 permutation functions added][v25_poseidon]. -//! Available via `CryptoHazmat` under the `hazmat-crypto` feature for advanced -//! cryptographic use cases. -//! -//! 4. [`contracttrait` macro added for reusable contract interfaces][v25_contracttrait]. -//! Define traits with default implementations using `#[contracttrait]`, then implement them -//! in contracts using `#[contractimpl(contracttrait)]`. -//! -//! 5. [Resource limit enforcement enabled by default in tests][v25_resource_limits]. -//! `Env::default()` now enforces Mainnet resource limits for contract invocations. -//! Tests will fail if limits are exceeded. This provides early warning of contracts that -//! may be too resource-heavy for Mainnet. If you see test failures after upgrading, -//! use `env.cost_estimate().disable_resource_limits()` to opt-out while optimizing. -//! -//! [v25_contracttrait]: v25_contracttrait -//! [v25_resource_limits]: v25_resource_limits -//! -//! # Migrating from v22 to v23 -//! -//! 1. [`contractevent` replaces `Events::publish`][v23_contractevent] -//! -//! 2. [`MuxedAddress` replaces `Address` as the `to` of the `TokenInterface::transfer`]. -//! This change concerns `soroban-token-sdk` and is documented in detail in -//! `soroban-token-sdk` crate migration guide. -//! -//! 3. [Accessing archived persistent entries in tests no longer results in a panic][v23_archived_testing], -//! automatic restoration is emulated instead. Note, that instance storage is a -//! persistent entry as well. -//! -//! # Migrating from v21 to v22 -//! -//! 1. [`Env::register`] and [`Env::register_at`] replace [`Env::register_contract`] and [`Env::register_contract_wasm`]. -//! -//! [`register`] registers both native contracts previously registered with -//! [`register_contract`] and Wasm contracts previously registered with -//! [`register_contract_wasm`]. It accepts a tuple that is passed to the -//! contracts constructor. Pass `()` if the contract has no constructor. -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, Env}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! // .. -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let address = env.register( -//! Contract, // 👈 👀 The contract being registered, or a Wasm `&[u8]`. -//! (), // 👈 👀 The constructor arguments, or (). -//! ); -//! // .. -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! [`register_at`] registers both native contracts previously registered -//! with [`register_contract`] and Wasm contracts previously registered with -//! [`register_contract_wasm`], and allows setting the address that the -//! contract is registered at. It accepts a tuple that is passed to the -//! contracts constructor. Pass `()` if the contract has no constructor. -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! // .. -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let address = Address::generate(&env); -//! env.register_at( -//! &address, // 👈 👀 The address to register the contract at. -//! Contract, // 👈 👀 The contract being registered, or a Wasm `&[u8]`. -//! (), // 👈 👀 The constructor arguments, or (). -//! ); -//! // .. -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! 2. [`DeployerWithAddress::deploy_v2`] replaces [`DeployerWithAddress::deploy`]. -//! -//! [`deploy_v2`] is the same as [`deploy`], except it accepts a list of -//! arguments to be passed to the contracts constructor that will be called -//! when it is deployed. For deploying existing contracts that do not have -//! constructors, pass `()`. -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, BytesN, Env}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn exec(env: Env, wasm_hash: BytesN<32>) { -//! let salt = [0u8; 32]; -//! let deployer = env.deployer().with_current_contract(salt); -//! // Pass `()` for contracts that have no contstructor, or have a -//! // constructor and require no arguments. Pass arguments in a -//! // tuple if any required. -//! let contract_address = deployer.deploy_v2(wasm_hash, ()); -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let contract_address = env.register(Contract, ()); -//! let contract = ContractClient::new(&env, &contract_address); -//! // Upload the contract code before deploying its instance. -//! const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); -//! let wasm_hash = env.deployer().upload_contract_wasm(WASM); -//! contract.exec(&wasm_hash); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! 2. Deprecated [`fuzz_catch_panic`]. Use [`Env::try_invoke_contract`] and the `try_` client functions instead. -//! -//! The `fuzz_catch_panic` function could be used in fuzz tests to catch a contract panic. Improved behavior can be found by invoking a contract with the `try_` variant of the invoke function contract clients. -//! -//! ``` -//! use libfuzzer_sys::fuzz_target; -//! use soroban_sdk::{contract, contracterror, contractimpl, Env, testutils::arbitrary::*}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contracterror] -//! #[derive(Debug, PartialEq)] -//! pub enum Error { -//! Overflow = 1, -//! } -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn add(x: u32, y: u32) -> Result { -//! x.checked_add(y).ok_or(Error::Overflow) -//! } -//! } -//! -//! #[derive(Arbitrary, Debug)] -//! pub struct Input { -//! pub x: u32, -//! pub y: u32, -//! } -//! -//! fuzz_target!(|input: Input| { -//! let env = Env::default(); -//! let id = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &id); -//! -//! let result = client.try_add(&input.x, &input.y); -//! match result { -//! // Returned if the function succeeds, and the value returned is -//! // the type expected. -//! Ok(Ok(_)) => {} -//! // Returned if the function succeeds, and the value returned is -//! // NOT the type expected. -//! Ok(Err(_)) => panic!("unexpected type"), -//! // Returned if the function fails, and the error returned is -//! // recognised as part of the contract errors enum. -//! Err(Ok(_)) => {} -//! // Returned if the function fails, and the error returned is NOT -//! // recognised, or the contract panic'd. -//! Err(Err(_)) => panic!("unexpected error"), -//! } -//! }); -//! -//! # fn main() { } -//! ``` -//! -//! 3. Events in test snapshots are now reduced to only contract events and system events. Diagnostic events will no longer appear in test snapshots. -//! -//! This will cause all test snapshot JSON files generated by the SDK to change when upgrading to this major version of the SDK. The change should be isolated to events and should omit only diagnostic events. -//! -//! [`Env::register`]: crate::Env::register -//! [`register`]: crate::Env::register -//! [`Env::register_at`]: crate::Env::register_at -//! [`register_at`]: crate::Env::register_at -//! [`Env::register_contract`]: crate::Env::register_contract -//! [`register_contract`]: crate::Env::register_contract -//! [`Env::register_contract_wasm`]: crate::Env::register_contract_wasm -//! [`register_contract_wasm`]: crate::Env::register_contract_wasm -//! [`DeployerWithAddress::deploy_v2`]: crate::deploy::DeployerWithAddress::deploy_v2 -//! [`deploy_v2`]: crate::deploy::DeployerWithAddress::deploy_v2 -//! [`DeployerWithAddress::deploy`]: crate::deploy::DeployerWithAddress::deploy -//! [`deploy`]: crate::deploy::DeployerWithAddress::deploy -//! [`fuzz_catch_panic`]: crate::testutils::arbitrary::fuzz_catch_panic -//! [`Env::try_invoke_contract`]: crate::Env::try_invoke_contract -//! -//! # Migrating from v20 to v21 -//! -//! 1. [`CustomAccountInterface::__check_auth`] function `signature_payload` parameter changes from type [`BytesN<32>`] to [`Hash<32>`]. -//! -//! The two types are ABI-compatible. [`Hash<32>`] contains a [`BytesN<32>`]. -//! For [`CustomAccountInterface::__check_auth`], the host constructs the -//! `signature_payload`, so it is guaranteed to contain bytes produced by the -//! host's authentication payload hash. This guarantee is specific to -//! host-managed `__check_auth` invocations and does not apply to general -//! contract entrypoint arguments. -//! -//! To convert from a [`Hash<32>`] to a [`BytesN<32>`], use [`Hash<32>::to_bytes`] or [`Into::into`]. -//! -//! Current implementations of the interface will see a build error, and should change [`BytesN<32>`] to [`Hash<32>`]. -//! -//! ``` -//! use soroban_sdk::{ -//! auth::{Context, CustomAccountInterface}, contract, -//! contracterror, contractimpl, crypto::Hash, Env, -//! Vec, -//! }; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contracterror] -//! pub enum Error { -//! AnError = 1, -//! // ... -//! } -//! -//! #[contractimpl] -//! impl CustomAccountInterface for Contract { -//! type Signature = (); -//! type Error = Error; -//! -//! fn __check_auth( -//! env: Env, -//! signature_payload: Hash<32>, // 👈 👀 -//! signatures: (), -//! auth_contexts: Vec, -//! ) -> Result<(), Self::Error> { -//! // ... -//! # todo!() -//! } -//! } -//! -//! # fn main() { } -//! ``` -//! -//! [`CustomAccountInterface::__check_auth`]: crate::auth::CustomAccountInterface::__check_auth -//! [`BytesN<32>`]: crate::BytesN -//! [`Hash<32>`]: crate::crypto::Hash -//! [`Hash<32>::to_bytes`]: crate::crypto::Hash::to_bytes - -pub mod v23_archived_testing; -pub mod v23_contractevent; -pub mod v25_bn254; -pub mod v25_contracttrait; -pub mod v25_event_testing; -pub mod v25_poseidon; -pub mod v25_resource_limits; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/address.rs b/temp_sdk/soroban-sdk-26.0.1/src/address.rs deleted file mode 100644 index 9522a0b..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/address.rs +++ /dev/null @@ -1,450 +0,0 @@ -use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; - -use super::{ - contracttype, env::internal::AddressObject, env::internal::Env as _, unwrap::UnwrapInfallible, - Bytes, BytesN, ConversionError, Env, IntoVal, String, TryFromVal, TryIntoVal, Val, Vec, -}; - -#[cfg(any(test, feature = "hazmat-address"))] -use crate::address_payload::AddressPayload; - -#[cfg(not(target_family = "wasm"))] -use crate::env::internal::xdr::{AccountId, ScVal}; -#[cfg(any(test, feature = "testutils", not(target_family = "wasm")))] -use crate::env::xdr::ScAddress; - -/// Address is a universal opaque identifier to use in contracts. -/// -/// Address can be used as an input argument (for example, to identify the -/// payment recipient), as a data key (for example, to store the balance), as -/// the authentication & authorization source (for example, to authorize the -/// token transfer) etc. -/// -/// See `require_auth` documentation for more details on using Address for -/// authorization. -/// -/// Internally, Address may represent a Stellar account or a contract. Contract -/// address may be used to identify the account contracts - special contracts -/// that allow customizing authentication logic and adding custom authorization -/// rules. -/// -/// In tests Addresses should be generated via `Address::generate()`. -#[derive(Clone)] -pub struct Address { - env: Env, - obj: AddressObject, -} - -impl Debug for Address { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - #[cfg(target_family = "wasm")] - write!(f, "Address(..)")?; - #[cfg(not(target_family = "wasm"))] - { - use crate::env::internal::xdr; - use stellar_strkey::{ed25519, Contract, Strkey}; - let sc_val = ScVal::try_from(self).map_err(|_| core::fmt::Error)?; - if let ScVal::Address(addr) = sc_val { - match addr { - xdr::ScAddress::Account(account_id) => { - let xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256( - ed25519, - ))) = account_id; - let strkey = Strkey::PublicKeyEd25519(ed25519::PublicKey(ed25519)); - write!(f, "AccountId({})", strkey.to_string())?; - } - xdr::ScAddress::Contract(xdr::ContractId(contract_id)) => { - let strkey = Strkey::Contract(Contract(contract_id.0)); - write!(f, "Contract({})", strkey.to_string())?; - } - ScAddress::MuxedAccount(_) - | ScAddress::ClaimableBalance(_) - | ScAddress::LiquidityPool(_) => { - return Err(core::fmt::Error); - } - } - } else { - return Err(core::fmt::Error); - } - } - Ok(()) - } -} - -impl Eq for Address {} - -impl PartialEq for Address { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for Address { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Address { - fn cmp(&self, other: &Self) -> Ordering { - #[cfg(not(target_family = "wasm"))] - if !self.env.is_same_env(&other.env) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = self - .env - .obj_cmp(self.obj.to_val(), other.obj.to_val()) - .unwrap_infallible(); - v.cmp(&0) - } -} - -impl TryFromVal for Address { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &AddressObject) -> Result { - Ok(unsafe { Address::unchecked_new(env.clone(), *val) }) - } -} - -impl TryFromVal for Address { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(AddressObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &Address) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&Address) -> Result { - Ok(v.to_val()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Address> for ScVal { - fn from(v: &Address) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From
for ScVal { - fn from(v: Address) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Address { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok( - AddressObject::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible(), - ) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Address> for ScAddress { - fn from(v: &Address) -> Self { - match ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() { - ScVal::Address(a) => a, - _ => panic!("expected ScVal::Address"), - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl From
for ScAddress { - fn from(v: Address) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Address { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScAddress) -> Result { - Ok(AddressObject::try_from_val( - env, - &Val::try_from_val(env, &ScVal::Address(val.clone()))?, - )? - .try_into_val(env) - .unwrap_infallible()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFrom<&Address> for AccountId { - type Error = ConversionError; - fn try_from(v: &Address) -> Result { - let sc: ScAddress = v.into(); - match sc { - ScAddress::Account(aid) => Ok(aid), - _ => Err(ConversionError), - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFrom
for AccountId { - type Error = ConversionError; - fn try_from(v: Address) -> Result { - (&v).try_into() - } -} - -#[contracttype(crate_path = "crate", export = false)] -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Executable { - Wasm(BytesN<32>), - StellarAsset, - Account, -} - -impl Address { - /// Ensures that this Address has authorized invocation of the current - /// contract with the provided arguments. - /// - /// During the on-chain execution the Soroban host will perform the needed - /// authentication (verify the signatures) and ensure the replay prevention. - /// The contracts don't need to perform this tasks. - /// - /// The arguments don't have to match the arguments of the contract - /// invocation. However, it's considered the best practice to have a - /// well-defined, deterministic and ledger-state-independent mapping between - /// the contract invocation arguments and `require_auth` arguments. This - /// will allow the contract callers to easily build the required signature - /// payloads and prevent potential authorization failures. - /// - /// ### Panics - /// - /// If the invocation is not authorized. - pub fn require_auth_for_args(&self, args: Vec) { - self.env.require_auth_for_args(self, args); - } - - /// Ensures that this Address has authorized invocation of the current - /// contract with all the invocation arguments - /// - /// This works exactly in the same fashion as `require_auth_for_args`, but - /// arguments are automatically inferred from the current contract - /// invocation. - /// - /// This is useful when there is only a single Address that needs to - /// authorize the contract invocation and there are no dynamic arguments - /// that don't need authorization. - /// - /// ### Panics - /// - /// If the invocation is not authorized. - pub fn require_auth(&self) { - self.env.require_auth(self); - } - - /// Creates an `Address` corresponding to the provided Stellar strkey. - /// - /// The only supported strkey types are account keys (`G...`) and contract keys (`C...`). Any - /// other valid or invalid strkey will cause this to panic. - /// - /// Prefer using the `Address` directly as input or output argument. Only - /// use this in special cases when addresses need to be shared between - /// different environments (e.g. different chains). - pub fn from_str(env: &Env, strkey: &str) -> Address { - Address::from_string(&String::from_str(env, strkey)) - } - - /// Creates an `Address` corresponding to the provided Stellar strkey. - /// - /// The only supported strkey types are account keys (`G...`) and contract keys (`C...`). Any - /// other valid or invalid strkey will cause this to panic. - /// - /// Prefer using the `Address` directly as input or output argument. Only - /// use this in special cases when addresses need to be shared between - /// different environments (e.g. different chains). - pub fn from_string(strkey: &String) -> Self { - let env = strkey.env(); - unsafe { - Self::unchecked_new( - env.clone(), - env.strkey_to_address(strkey.to_object().to_val()) - .unwrap_infallible(), - ) - } - } - - /// Creates an `Address` corresponding to the provided Stellar strkey bytes. - /// - /// This behaves exactly in the same fashion as `from_strkey`, i.e. the bytes should contain - /// exactly the same contents as `String` would (i.e. base-32 ASCII string). - /// - /// The only supported strkey types are account keys (`G...`) and contract keys (`C...`). Any - /// other valid or invalid strkey will cause this to panic. - /// - /// Prefer using the `Address` directly as input or output argument. Only - /// use this in special cases when addresses need to be shared between - /// different environments (e.g. different chains). - pub fn from_string_bytes(strkey: &Bytes) -> Self { - let env = strkey.env(); - unsafe { - Self::unchecked_new( - env.clone(), - env.strkey_to_address(strkey.to_object().to_val()) - .unwrap_infallible(), - ) - } - } - - /// Returns the executable type of this address, if any. - /// - /// Returns None when the contract or account does not exist. - /// - /// For Wasm contracts, this also returns the hash of the contract code. - /// Otherwise, this just returns which kind of 'built-in' executable this is - /// (StellarAsset or Account). - pub fn executable(&self) -> Option { - let executable_val: Val = - Env::get_address_executable(&self.env, self.obj).unwrap_infallible(); - executable_val.into_val(&self.env) - } - - /// Returns whether this address exists in the ledger. - /// - /// For the contract addresses, this means that there is a corresponding - /// contract instance deployed. For account addresses, this means that the - /// account entry exists in the ledger. - pub fn exists(&self) -> bool { - let executable_val: Val = - Env::get_address_executable(&self.env, self.obj).unwrap_infallible(); - !executable_val.is_void() - } - - /// Converts this `Address` into the corresponding Stellar strkey. - pub fn to_string(&self) -> String { - String::try_from_val( - &self.env, - &self.env.address_to_strkey(self.obj).unwrap_infallible(), - ) - .unwrap_optimized() - } - - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: AddressObject) -> Self { - Self { env, obj } - } - - #[inline(always)] - pub fn env(&self) -> &Env { - &self.env - } - - pub fn as_val(&self) -> &Val { - self.obj.as_val() - } - - pub fn to_val(&self) -> Val { - self.obj.to_val() - } - - pub fn as_object(&self) -> &AddressObject { - &self.obj - } - - pub fn to_object(&self) -> AddressObject { - self.obj - } - - /// Extracts the payload from the address. - /// - /// Returns: - /// - For contract addresses (C...), returns [`AddressPayload::ContractIdHash`] - /// containing the 32-byte contract hash. - /// - For account addresses (G...), returns [`AddressPayload::AccountIdPublicKeyEd25519`] - /// containing the 32-byte Ed25519 public key. - /// - /// Returns `None` if the address type is not recognized. This may occur if - /// a new address type has been introduced to the network that this version - /// of this library is not aware of. - /// - /// # Warning - /// - /// For account addresses, the returned Ed25519 public key corresponds to - /// the account's master key, which depending on the configuration of that - /// account may or may not be a signer of the account. Do not use this for - /// custom Ed25519 signature verification as a form of authentication - /// because the master key may not be configured the signer of the account. - #[cfg(any(test, feature = "hazmat-address"))] - #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))] - pub fn to_payload(&self) -> Option { - AddressPayload::from_address(self) - } - - /// Constructs an [`Address`] from an [`AddressPayload`]. - /// - /// This is the inverse of [`to_payload`][Address::to_payload]. - /// - /// # Warning - /// - /// For account addresses, the returned Ed25519 public key corresponds to - /// the account's master key, which depending on the configuration of that - /// account may or may not be a signer of the account. Do not use this for - /// custom Ed25519 signature verification as a form of authentication - /// because the master key may not be configured the signer of the account. - #[cfg(any(test, feature = "hazmat-address"))] - #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))] - pub fn from_payload(env: &Env, payload: AddressPayload) -> Address { - payload.to_address(env) - } -} - -#[cfg(any(not(target_family = "wasm"), test, feature = "testutils"))] -use crate::env::xdr::{ContractId, Hash}; -use crate::unwrap::UnwrapOptimized; - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl crate::testutils::Address for Address { - fn generate(env: &Env) -> Self { - Self::try_from_val( - env, - &ScAddress::Contract(ContractId(Hash(env.with_generator(|mut g| g.address())))), - ) - .unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl Address { - pub(crate) fn contract_id(&self) -> ContractId { - let sc_address: ScAddress = self.try_into().unwrap(); - if let ScAddress::Contract(c) = sc_address { - c - } else { - panic!("address is not a contract {:?}", self); - } - } - - pub(crate) fn from_contract_id(env: &Env, contract_id: [u8; 32]) -> Self { - Self::try_from_val(env, &ScAddress::Contract(ContractId(Hash(contract_id)))).unwrap() - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs b/temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs deleted file mode 100644 index e0ca0ed..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/address_payload.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![cfg(any(test, feature = "hazmat-address"))] -#![cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-address")))] - -//! Address payload extraction and construction. -//! -//! This module provides types and functions for extracting raw payloads from -//! addresses and constructing addresses from raw payloads. This is useful for -//! cross-chain interoperability where raw addresses need to be passed between -//! different systems. -//! -//! # Warning -//! -//! For account addresses, the returned Ed25519 public key corresponds to -//! the account's master key, which depending on the configuration of that -//! account may or may not be a signer of the account. Do not use this for -//! custom Ed25519 signature verification as a form of authentication -//! because the master key may not be configured the signer of the account. - -use crate::{unwrap::UnwrapOptimized, Address, Bytes, BytesN, Env}; - -/// The payload contained in an [`Address`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum AddressPayload { - /// A 32-byte Ed25519 public key from an account address (G...). - /// - /// # Warning - /// - /// The Ed25519 public key corresponds to the account's master key, which - /// depending on the configuration of that account may or may not be a - /// signer of the account. Do not use this for custom Ed25519 signature - /// verification as a form of authentication. - AccountIdPublicKeyEd25519(BytesN<32>), - /// A 32-byte contract hash from a contract address (C...). - ContractIdHash(BytesN<32>), -} - -impl AddressPayload { - /// Constructs an [`Address`] from this payload. - /// - /// This is the inverse of [`from_address`][AddressPayload::from_address]. - /// - /// # Warning - /// - /// For account addresses, the returned Ed25519 public key corresponds to - /// the account's master key, which depending on the configuration of that - /// account may or may not be a signer of the account. Do not use this for - /// custom Ed25519 signature verification as a form of authentication - /// because the master key may not be configured the signer of the account. - pub fn to_address(&self, env: &Env) -> Address { - use crate::xdr::FromXdr; - // Build XDR header and get payload bytes based on payload type: - let (header, payload_bytes) = match self { - AddressPayload::AccountIdPublicKeyEd25519(bytes) => ( - [ - 0, 0, 0, 18, // ScVal::Address - 0, 0, 0, 0, // ScAddress::Account - 0, 0, 0, 0, // PublicKey::PublicKeyTypeEd25519 - ] - .as_slice(), - bytes.as_bytes(), - ), - AddressPayload::ContractIdHash(bytes) => ( - [ - 0, 0, 0, 18, // ScVal::Address - 0, 0, 0, 1, // ScAddress::Contract - ] - .as_slice(), - bytes.as_bytes(), - ), - }; - - let mut xdr = Bytes::from_slice(env, header); - xdr.append(payload_bytes); - - Address::from_xdr(env, &xdr).unwrap_optimized() - } - - /// Extracts an [`AddressPayload`] from an [`Address`]. - /// - /// Returns: - /// - For contract addresses (C...), returns [`AddressPayload::ContractIdHash`] - /// containing the 32-byte contract hash. - /// - For account addresses (G...), returns [`AddressPayload::AccountIdPublicKeyEd25519`] - /// containing the 32-byte Ed25519 public key. - /// - /// Returns `None` if the address type is not recognized. This may occur if - /// a new address type has been introduced to the network that this version - /// of this library is not aware of. - /// - /// # Warning - /// - /// For account addresses, the returned Ed25519 public key corresponds to - /// the account's master key, which depending on the configuration of that - /// account may or may not be a signer of the account. Do not use this for - /// custom Ed25519 signature verification as a form of authentication - /// because the master key may not be configured the signer of the account. - pub fn from_address(address: &Address) -> Option { - use crate::xdr::ToXdr; - let xdr = address.to_xdr(address.env()); - // Skip over ScVal discriminant because we know it is an ScAddress. - let xdr = xdr.slice(4..); - // Decode ScAddress - let addr_type: BytesN<4> = xdr.slice(0..4).try_into().unwrap_optimized(); - match addr_type.to_array() { - // Decode ScAddress::Account - [0, 0, 0, 0] => { - // Decode PublicKey - let public_key_type: BytesN<4> = xdr.slice(4..8).try_into().unwrap_optimized(); - match public_key_type.to_array() { - // Decode PublicKey::PublicKeyTypeEd25519 - [0, 0, 0, 0] => { - let ed25519: BytesN<32> = xdr.slice(8..40).try_into().unwrap_optimized(); - Some(AddressPayload::AccountIdPublicKeyEd25519(ed25519)) - } - _ => None, - } - } - // Decode ScAddress::Contract - [0, 0, 0, 1] => { - let hash: BytesN<32> = xdr.slice(4..36).try_into().unwrap_optimized(); - Some(AddressPayload::ContractIdHash(hash)) - } - _ => None, - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs b/temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs deleted file mode 100644 index bd9b0bb..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/alloc/bump_pointer.rs +++ /dev/null @@ -1,122 +0,0 @@ -// This code is adapted from https://github.com/wenyuzhao/bump-allocator-rs -// -// We've altered it to work entirely with usize values internally and only cast -// back to an exposed-provenance pointer when returning from alloc. This gives -// us a richer checked-arithmetic API we can use to trap overflows internally, -// and also avoids some potential UB issues with pointer provenance. Since the -// provenance of __heap_base is a 1-byte value anyway, and all the rest of the -// wasm heap is considered to have exposed provenance, we think this is the best -// we can do. Writing allocators is tricky! -// -// NB: technically these alterations only handle corner cases that cannot be hit -// using safe client code. Safe clients pass `Layout` structs that always meet -// additional size and alignment constraints. But hardening the code to tolerate -// even _unsafe_ inputs -- malformed `Layout` inputs one can only create by -// calling unsafe methods -- is not only easy to do, it makes the code simpler -// and more readable, so we went ahead and did it. - -use crate::unwrap::UnwrapOptimized; -use core::alloc::{GlobalAlloc, Layout}; - -#[global_allocator] -static GLOBAL: BumpPointer = BumpPointer; - -struct BumpPointer; - -// Safety: The mutable reference to LOCAL_ALLOCATOR in GlobalAlloc::alloc is -// safe because: -// -// 1. This code only runs on wasm32, which is single-threaded — no concurrent -// access is possible. -// 2. The reference is narrowly scoped — it is created, used for a single -// method call, and immediately dropped within GlobalAlloc::alloc. -// 3. Reentrancy cannot occur — none of the code called through -// BumpPointerLocal::alloc can allocate (it is all simple integer -// arithmetic and wasm intrinsics), so the global allocator will not -// be re-entered while the reference is live. -// -// See: https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html#safe-references -static mut LOCAL_ALLOCATOR: BumpPointerLocal = BumpPointerLocal::new(); - -unsafe impl GlobalAlloc for BumpPointer { - #[inline(always)] - #[allow(static_mut_refs)] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - let (bytes, align) = (layout.size(), layout.align()); - let ptr = LOCAL_ALLOCATOR.alloc(bytes, align); - core::ptr::with_exposed_provenance_mut(ptr) - } - - // No-op. See the module-level documentation on `crate::alloc` for details. - #[inline(always)] - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} -} - -struct BumpPointerLocal { - cursor: usize, - limit: usize, -} - -impl BumpPointerLocal { - const LOG_PAGE_SIZE: usize = 16; - const PAGE_SIZE: usize = 1 << Self::LOG_PAGE_SIZE; // 64KB - const MEM: u32 = 0; // Memory 0 is the only legal one currently - - pub const fn new() -> Self { - Self { - cursor: 0, - limit: 0, - } - } - - #[inline(always)] - fn maybe_init_inline(&mut self) { - if self.limit == 0 { - // This is a slight over-estimate and ideally we would use __heap_base - // but that seems not to be easy to access and in any case it is just a - // convention whereas this is more guaranteed by the wasm spec to work. - self.cursor = core::arch::wasm32::memory_size(Self::MEM) - .checked_mul(Self::PAGE_SIZE) - .unwrap_optimized(); - self.limit = self.cursor; - } - } - - #[inline(never)] - fn maybe_init(&mut self) { - self.maybe_init_inline() - } - - // Allocate `bytes` bytes with `align` alignment. - #[inline(always)] - fn alloc(&mut self, bytes: usize, align: usize) -> usize { - self.maybe_init(); - let start = self - .cursor - .checked_next_multiple_of(align) - .unwrap_optimized(); - let new_cursor = start.checked_add(bytes).unwrap_optimized(); - if new_cursor <= self.limit { - self.cursor = new_cursor; - start - } else { - self.alloc_slow(bytes, align) - } - } - - #[inline(always)] - fn alloc_slow_inline(&mut self, bytes: usize, align: usize) -> usize { - let pages = bytes.div_ceil(Self::PAGE_SIZE); - if core::arch::wasm32::memory_grow(Self::MEM, pages) == usize::MAX { - core::arch::wasm32::unreachable(); - } - let bytes_grown = pages.checked_mul(Self::PAGE_SIZE).unwrap_optimized(); - self.limit = self.limit.checked_add(bytes_grown).unwrap_optimized(); - self.alloc(bytes, align) - } - - #[inline(never)] - fn alloc_slow(&mut self, bytes: usize, align: usize) -> usize { - self.alloc_slow_inline(bytes, align) - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs b/temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs deleted file mode 100644 index eff6be1..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/alloc/mod.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Allocator used by contracts built with the `alloc` feature. -//! -//! The `alloc` feature is **disabled by default**. It exists to support a -//! use-case that is both expensive (in terms of CPU time and code size) and -//! typically unnecessary: allocating unbounded memory, dynamically, in the wasm -//! guest's linear-memory heap. Soroban was designed to avoid this need most of -//! the time: host objects like [`Vec`](crate::Vec), [`Map`](crate::Map), or -//! [`Bytes`](crate::Bytes) already support dynamic growth, but live in the host -//! heap and are efficient to use from the guest without any guest memory -//! allocator. Moreover even if a contract _does_ want guest-memory storage of -//! dynamic data, it can accomplish it in bounded static memory using a crate -//! like [`heapless`](https://crates.io/crates/heapless). Turning on the `alloc` -//! feature should usually be the last choice for contracts with no better -//! option. -//! -//! # Enabling -//! -//! Add the `alloc` feature to `soroban-sdk` in your `Cargo.toml`: -//! -//! ```toml -//! [dependencies] -//! soroban-sdk = { version = "...", features = ["alloc"] } -//! ``` -//! -//! With the feature enabled the SDK registers a global bump-pointer allocator -//! that services all allocations made through Rust's [`alloc`](alloc_crate) -//! APIs. This makes heap-allocated types such as `::alloc::vec::Vec` and -//! `::alloc::string::String` available inside contracts, and enables SDK helpers -//! that require allocation (e.g. [`Bytes::to_alloc_vec`]). -//! -//! [alloc_crate]: https://doc.rust-lang.org/alloc/ -//! [`Bytes::to_alloc_vec`]: crate::Bytes::to_alloc_vec -//! -//! # Using a Custom Allocator -//! -//! The bump-pointer allocator provided by the `alloc` feature is just one -//! possible implementation. A contract is free to define its own global -//! allocator by implementing [`GlobalAlloc`] and registering it with the -//! [`#[global_allocator]`](macro@global_allocator) attribute. See the -//! [Rust `GlobalAlloc` documentation][global_alloc_docs] for details. -//! -//! If you supply your own allocator there is no need to enable the `alloc` -//! feature. -//! -//! [`GlobalAlloc`]: core::alloc::GlobalAlloc -//! [global_alloc_docs]: https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html -//! -//! # How the `alloc` Allocator Works -//! -//! The `alloc` allocator is a simple bump-pointer (arena) allocator. Each call to -//! `alloc` advances a cursor through Wasm linear memory, growing the memory as -//! needed. **`dealloc` is a no-op** — memory is never freed during contract -//! execution. All allocations made during an invocation persist until the host -//! destroys the VM instance at the end of the invocation. -//! -//! This design is a good fit for Soroban contracts because each invocation runs -//! to completion and then the entire VM is discarded. There is no long-lived -//! process that would benefit from returning memory to the allocator. - -#[cfg(target_family = "wasm")] -mod bump_pointer; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs b/temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs deleted file mode 100644 index 9e05794..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/arbitrary_extra.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Extra trait impls required by the bounds to `SorobanArbitrary`. -//! -//! These are in their own module so that they are defined even when "testutils" -//! is not configured, making type inference consistent between configurations. - -use crate::ConversionError; -use crate::Error; -use crate::{Env, TryFromVal}; - -impl TryFromVal for u32 { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &u32) -> Result { - Ok(*v) - } -} - -impl TryFromVal for i32 { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &i32) -> Result { - Ok(*v) - } -} - -impl TryFromVal for u64 { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &u64) -> Result { - Ok(*v) - } -} - -impl TryFromVal for i64 { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &i64) -> Result { - Ok(*v) - } -} - -impl TryFromVal for u128 { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &u128) -> Result { - Ok(*v) - } -} - -impl TryFromVal for i128 { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &i128) -> Result { - Ok(*v) - } -} - -impl TryFromVal for bool { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &bool) -> Result { - Ok(*v) - } -} - -impl TryFromVal for () { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &()) -> Result { - Ok(*v) - } -} - -impl TryFromVal for Error { - type Error = ConversionError; - fn try_from_val(_env: &Env, v: &Error) -> Result { - Ok(*v) - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/auth.rs b/temp_sdk/soroban-sdk-26.0.1/src/auth.rs deleted file mode 100644 index 035d514..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/auth.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Auth contains types for building custom account contracts. - -use crate::{ - contractimpl_trait_macro, contracttype, crypto::Hash, Address, BytesN, Env, Error, Symbol, Val, - Vec, -}; - -/// Context of a single authorized call performed by an address. -/// -/// Custom account contracts that implement `__check_auth` special function -/// receive a list of `Context` values corresponding to all the calls that -/// need to be authorized. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub enum Context { - /// Contract invocation. - Contract(ContractContext), - /// Contract that has a constructor with no arguments is created. - CreateContractHostFn(CreateContractHostFnContext), - /// Contract that has a constructor with 1 or more arguments is created. - CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext), -} - -/// Authorization context of a single contract call. -/// -/// This struct corresponds to a `require_auth_for_args` call for an address -/// from `contract` function with `fn_name` name and `args` arguments. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub struct ContractContext { - pub contract: Address, - pub fn_name: Symbol, - pub args: Vec, -} - -/// Authorization context for `create_contract` host function that creates a -/// new contract on behalf of authorizer address. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub struct CreateContractHostFnContext { - pub executable: ContractExecutable, - pub salt: BytesN<32>, -} - -/// Authorization context for `create_contract` host function that creates a -/// new contract on behalf of authorizer address. -/// This is the same as `CreateContractHostFnContext`, but also has -/// contract constructor arguments. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub struct CreateContractWithConstructorHostFnContext { - pub executable: ContractExecutable, - pub salt: BytesN<32>, - pub constructor_args: Vec, -} - -/// Contract executable used for creating a new contract and used in -/// `CreateContractHostFnContext`. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub enum ContractExecutable { - Wasm(BytesN<32>), -} - -/// A node in the tree of authorizations performed on behalf of the current -/// contract as invoker of the contracts deeper in the call stack. -/// -/// This is used as an argument of `authorize_as_current_contract` host function. -/// -/// This tree corresponds `require_auth[_for_args]` calls on behalf of the -/// current contract. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub enum InvokerContractAuthEntry { - /// Invoke a contract. - Contract(SubContractInvocation), - /// Create a contract passing 0 arguments to constructor. - CreateContractHostFn(CreateContractHostFnContext), - /// Create a contract passing 0 or more arguments to constructor. - CreateContractWithCtorHostFn(CreateContractWithConstructorHostFnContext), -} - -/// Value of contract node in InvokerContractAuthEntry tree. -#[derive(Clone)] -#[contracttype(crate_path = "crate", export = false)] -pub struct SubContractInvocation { - pub context: ContractContext, - pub sub_invocations: Vec, -} - -/// Custom account interface that a contract implements to support being used -/// as a custom account for auth. -/// -/// Once a contract implements the interface, call to [`Address::require_auth`] -/// for the contract's address will call its `__check_auth` implementation. -#[contractimpl_trait_macro(crate_path = "crate")] -pub trait CustomAccountInterface { - type Signature; - type Error: Into; - - /// Check that the signatures and auth contexts are valid. - fn __check_auth( - env: Env, - signature_payload: Hash<32>, - signatures: Self::Signature, - auth_contexts: Vec, - ) -> Result<(), Self::Error>; -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/bytes.rs b/temp_sdk/soroban-sdk-26.0.1/src/bytes.rs deleted file mode 100644 index 511d1b7..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/bytes.rs +++ /dev/null @@ -1,1839 +0,0 @@ -#[cfg(feature = "alloc")] -extern crate alloc; - -use core::{ - borrow::Borrow, - cmp::Ordering, - convert::Infallible, - fmt::Debug, - iter::FusedIterator, - ops::{Bound, RangeBounds}, -}; - -use super::{ - env::internal::{BytesObject, Env as _, EnvBase as _}, - env::IntoVal, - ConversionError, Env, String, TryFromVal, TryIntoVal, Val, -}; - -use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; -#[cfg(doc)] -use crate::{storage::Storage, Map, Vec}; - -#[cfg(not(target_family = "wasm"))] -use super::xdr::ScVal; - -/// Create a [Bytes] with an array, or an integer or hex literal. -/// -/// The first argument in the list must be a reference to an [Env]. -/// -/// The second argument can be an [u8] array, or an integer literal of unbounded -/// size in any form: base10, hex, etc. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{Env, bytes}; -/// -/// let env = Env::default(); -/// let bytes = bytes!(&env, 0xfded3f55dec47250a52a8c0bb7038e72fa6ffaae33562f77cd2b629ef7fd424d); -/// assert_eq!(bytes.len(), 32); -/// ``` -/// -/// ``` -/// use soroban_sdk::{Env, bytes}; -/// -/// let env = Env::default(); -/// let bytes = bytes!(&env, [2, 0]); -/// assert_eq!(bytes.len(), 2); -/// ``` -/// -/// ``` -/// use soroban_sdk::{Env, bytes}; -/// -/// let env = Env::default(); -/// let bytes = bytes!(&env); -/// assert_eq!(bytes.len(), 0); -/// ``` -#[macro_export] -macro_rules! bytes { - ($env:expr $(,)?) => { - $crate::Bytes::new($env) - }; - ($env:expr, [$($x:expr),+ $(,)?] $(,)?) => { - $crate::Bytes::from_array($env, &[$($x),+]) - }; - ($env:expr, $x:tt $(,)?) => { - $crate::Bytes::from_array($env, &$crate::reexports_for_macros::bytes_lit::bytes!($x)) - }; -} - -/// Create a [BytesN] with an array, or an integer or hex literal. -/// -/// The first argument in the list must be a reference to an [Env]. -/// -/// The second argument can be an [u8] array, or an integer literal of unbounded -/// size in any form: base10, hex, etc. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{Env, bytesn}; -/// -/// let env = Env::default(); -/// let bytes = bytesn!(&env, 0xfded3f55dec47250a52a8c0bb7038e72fa6ffaae33562f77cd2b629ef7fd424d); -/// assert_eq!(bytes.len(), 32); -/// ``` -/// -/// ``` -/// use soroban_sdk::{Env, bytesn}; -/// -/// let env = Env::default(); -/// let bytes = bytesn!(&env, [2, 0]); -/// assert_eq!(bytes.len(), 2); -/// ``` -#[macro_export] -macro_rules! bytesn { - ($env:expr, [$($x:expr),+ $(,)?] $(,)?) => { - $crate::BytesN::from_array($env, &[$($x),+]) - }; - ($env:expr, $x:tt $(,)?) => { - $crate::BytesN::from_array($env, &$crate::reexports_for_macros::bytes_lit::bytes!($x)) - }; -} - -/// Internal macro that generates all `BytesN` wrapper methods and trait impls -/// *except* `from_bytes`. Types using this macro must provide their own -/// `from_bytes(BytesN<$size>) -> Self` (e.g. to add validation). -#[doc(hidden)] -macro_rules! impl_bytesn_repr { - ($elem: ident, $size: expr) => { - impl $elem { - pub fn into_bytes(self) -> BytesN<$size> { - self.0 - } - - pub fn to_bytes(&self) -> BytesN<$size> { - self.0.clone() - } - - pub fn as_bytes(&self) -> &BytesN<$size> { - &self.0 - } - - pub fn to_array(&self) -> [u8; $size] { - self.0.to_array() - } - - pub fn from_array(env: &Env, array: &[u8; $size]) -> Self { - Self::from_bytes(BytesN::from_array(env, array)) - } - - pub fn as_val(&self) -> &Val { - self.0.as_val() - } - - pub fn to_val(&self) -> Val { - self.0.to_val() - } - - pub fn as_object(&self) -> &BytesObject { - self.0.as_object() - } - - pub fn to_object(&self) -> BytesObject { - self.0.to_object() - } - } - - impl TryFromVal for $elem { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - let bytes = BytesN::try_from_val(env, val)?; - Ok(Self::from_bytes(bytes)) - } - } - - impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, elt: &$elem) -> Result { - Ok(elt.to_val()) - } - } - - impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, elt: &&$elem) -> Result { - Ok(elt.to_val()) - } - } - - #[cfg(not(target_family = "wasm"))] - impl From<&$elem> for ScVal { - fn from(v: &$elem) -> Self { - Self::from(&v.0) - } - } - - #[cfg(not(target_family = "wasm"))] - impl From<$elem> for ScVal { - fn from(v: $elem) -> Self { - (&v).into() - } - } - - impl IntoVal> for $elem { - fn into_val(&self, _e: &Env) -> BytesN<$size> { - self.0.clone() - } - } - - impl From<$elem> for Bytes { - fn from(v: $elem) -> Self { - v.0.into() - } - } - - impl From<$elem> for BytesN<$size> { - fn from(v: $elem) -> Self { - v.0 - } - } - - impl Into<[u8; $size]> for $elem { - fn into(self) -> [u8; $size] { - self.0.into() - } - } - - impl Eq for $elem {} - - impl PartialEq for $elem { - fn eq(&self, other: &Self) -> bool { - self.0.partial_cmp(other.as_bytes()) == Some(Ordering::Equal) - } - } - - impl Debug for $elem { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}({:?})", stringify!($elem), self.to_array()) - } - } - }; -} - -/// Bytes is a contiguous growable array type containing `u8`s. -/// -/// The array is stored in the Host and available to the Guest through the -/// functions defined on Bytes. -/// -/// Bytes values can be stored as [Storage], or in other types like [Vec], -/// [Map], etc. -/// -/// ### Examples -/// -/// Bytes values can be created from slices: -/// ``` -/// use soroban_sdk::{Bytes, Env}; -/// -/// let env = Env::default(); -/// let bytes = Bytes::from_slice(&env, &[1; 32]); -/// assert_eq!(bytes.len(), 32); -/// let mut slice = [0u8; 32]; -/// bytes.copy_into_slice(&mut slice); -/// assert_eq!(slice, [1u8; 32]); -/// ``` -#[derive(Clone)] -pub struct Bytes { - env: Env, - obj: BytesObject, -} - -impl Debug for Bytes { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Bytes(")?; - let mut iter = self.iter(); - if let Some(x) = iter.next() { - write!(f, "{:?}", x)?; - } - for x in iter { - write!(f, ", {:?}", x)?; - } - write!(f, ")")?; - Ok(()) - } -} - -impl Eq for Bytes {} - -impl PartialEq for Bytes { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for Bytes { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Bytes { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - #[cfg(not(target_family = "wasm"))] - if !self.env.is_same_env(&other.env) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = self - .env - .obj_cmp(self.obj.to_val(), other.obj.to_val()) - .unwrap_infallible(); - v.cmp(&0) - } -} - -impl TryFromVal for Bytes { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &Bytes) -> Result { - Ok(v.clone()) - } -} - -impl TryFromVal for Bytes { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &BytesObject) -> Result { - Ok(unsafe { Bytes::unchecked_new(env.clone(), *val) }) - } -} - -impl TryFromVal for Bytes { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(BytesObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &Bytes) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&Bytes) -> Result { - Ok(v.to_val()) - } -} - -impl From for Val { - #[inline(always)] - fn from(v: Bytes) -> Self { - v.obj.into() - } -} - -impl From for BytesObject { - #[inline(always)] - fn from(v: Bytes) -> Self { - v.obj - } -} - -impl From<&Bytes> for BytesObject { - #[inline(always)] - fn from(v: &Bytes) -> Self { - v.obj - } -} - -impl From<&Bytes> for Bytes { - #[inline(always)] - fn from(v: &Bytes) -> Self { - v.clone() - } -} - -impl From<&Bytes> for String { - fn from(v: &Bytes) -> Self { - Env::bytes_to_string(&v.env, v.obj.clone()) - .unwrap_infallible() - .into_val(&v.env) - } -} - -impl From for String { - fn from(v: Bytes) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Bytes> for ScVal { - fn from(v: &Bytes) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for ScVal { - fn from(v: Bytes) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Bytes { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok( - BytesObject::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible(), - ) - } -} - -impl TryFromVal for Bytes { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &&str) -> Result { - Ok(Bytes::from_slice(env, v.as_bytes())) - } -} - -impl TryFromVal for Bytes { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &&[u8]) -> Result { - Ok(Bytes::from_slice(env, v)) - } -} - -impl TryFromVal for Bytes { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &[u8; N]) -> Result { - Ok(Bytes::from_array(env, v)) - } -} - -impl Bytes { - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: BytesObject) -> Self { - Self { env, obj } - } - - #[inline(always)] - pub fn env(&self) -> &Env { - &self.env - } - - pub fn as_val(&self) -> &Val { - self.obj.as_val() - } - - pub fn to_val(&self) -> Val { - self.obj.to_val() - } - - pub fn as_object(&self) -> &BytesObject { - &self.obj - } - - pub fn to_object(&self) -> BytesObject { - self.obj - } -} - -impl Bytes { - /// Create an empty Bytes. - #[inline(always)] - pub fn new(env: &Env) -> Bytes { - let obj = env.bytes_new().unwrap_infallible(); - unsafe { Self::unchecked_new(env.clone(), obj) } - } - - /// Create a Bytes from the array. - #[inline(always)] - pub fn from_array(env: &Env, items: &[u8; N]) -> Bytes { - Self::from_slice(env, items) - } - - /// Create a Bytes from the slice. - #[inline(always)] - pub fn from_slice(env: &Env, items: &[u8]) -> Bytes { - Bytes { - env: env.clone(), - obj: env.bytes_new_from_slice(items).unwrap_optimized(), - } - } - - /// Sets the byte at the position with new value. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn set(&mut self, i: u32, v: u8) { - let v32: u32 = v.into(); - self.obj = self - .env() - .bytes_put(self.obj, i.into(), v32.into()) - .unwrap_infallible() - } - - /// Returns the byte at the position or None if out-of-bounds. - #[inline(always)] - pub fn get(&self, i: u32) -> Option { - if i < self.len() { - Some(self.get_unchecked(i)) - } else { - None - } - } - - /// Returns the byte at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn get_unchecked(&self, i: u32) -> u8 { - let res32_val = self.env().bytes_get(self.obj, i.into()).unwrap_infallible(); - let res32: u32 = res32_val.into(); - res32 as u8 - } - - /// Returns true if the Bytes is empty and has a length of zero. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the number of bytes are in the Bytes. - #[inline(always)] - pub fn len(&self) -> u32 { - self.env().bytes_len(self.obj).unwrap_infallible().into() - } - - /// Returns the first byte or None if empty. - #[inline(always)] - pub fn first(&self) -> Option { - if !self.is_empty() { - Some(self.first_unchecked()) - } else { - None - } - } - - /// Returns the first byte. - /// - /// ### Panics - /// - /// If the Bytes is empty. - #[inline(always)] - pub fn first_unchecked(&self) -> u8 { - let res: u32 = self.env().bytes_front(self.obj).unwrap_infallible().into(); - res as u8 - } - - /// Returns the last byte or None if empty. - #[inline(always)] - pub fn last(&self) -> Option { - if !self.is_empty() { - Some(self.last_unchecked()) - } else { - None - } - } - - /// Returns the last byte. - /// - /// ### Panics - /// - /// If the Bytes is empty. - #[inline(always)] - pub fn last_unchecked(&self) -> u8 { - let res: u32 = self.env().bytes_back(self.obj).unwrap_infallible().into(); - res as u8 - } - - /// Removes the byte at the position. - /// - /// Returns `None` if out-of-bounds. - #[inline(always)] - pub fn remove(&mut self, i: u32) -> Option<()> { - if i < self.len() { - self.remove_unchecked(i); - Some(()) - } else { - None - } - } - - /// Removes the byte at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn remove_unchecked(&mut self, i: u32) { - self.obj = self.env().bytes_del(self.obj, i.into()).unwrap_infallible() - } - - /// Adds the byte to the back. - /// - /// Increases the length by one and puts the byte in the last position. - #[inline(always)] - pub fn push_back(&mut self, x: u8) { - let x32: u32 = x.into(); - self.obj = self - .env() - .bytes_push(self.obj, x32.into()) - .unwrap_infallible() - } - - /// Removes and returns the last byte or None if empty. - #[inline(always)] - pub fn pop_back(&mut self) -> Option { - let last = self.last()?; - self.obj = self.env().bytes_pop(self.obj).unwrap_infallible(); - Some(last) - } - - /// Removes and returns the last byte or None if empty. - /// - /// ### Panics - /// - /// If the Bytes is empty. - #[inline(always)] - pub fn pop_back_unchecked(&mut self) -> u8 { - let last = self.last_unchecked(); - self.obj = self.env().bytes_pop(self.obj).unwrap_infallible(); - last - } - - /// Insert the byte at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn insert(&mut self, i: u32, b: u8) { - let b32: u32 = b.into(); - self.obj = self - .env() - .bytes_insert(self.obj, i.into(), b32.into()) - .unwrap_infallible() - } - - /// Insert the bytes at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn insert_from_bytes(&mut self, i: u32, bytes: Bytes) { - let mut result = self.slice(..i); - result.append(&bytes); - result.append(&self.slice(i..)); - *self = result - } - - /// Insert the bytes at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn insert_from_array(&mut self, i: u32, array: &[u8; N]) { - self.insert_from_slice(i, array) - } - - /// Insert the bytes at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn insert_from_slice(&mut self, i: u32, slice: &[u8]) { - self.insert_from_bytes(i, Bytes::from_slice(self.env(), slice)) - } - - /// Append the bytes. - #[inline(always)] - pub fn append(&mut self, other: &Bytes) { - self.obj = self - .env() - .bytes_append(self.obj, other.obj) - .unwrap_infallible() - } - - /// Extend with the bytes in the array. - #[inline(always)] - pub fn extend_from_array(&mut self, array: &[u8; N]) { - self.extend_from_slice(array) - } - - /// Extend with the bytes in the slice. - #[inline(always)] - pub fn extend_from_slice(&mut self, slice: &[u8]) { - self.obj = self - .env() - .bytes_copy_from_slice(self.to_object(), self.len().into(), slice) - .unwrap_optimized() - } - - /// Copy the bytes from slice. - /// - /// The full number of bytes in slice are always copied and [Bytes] is grown - /// if necessary. - #[inline(always)] - pub fn copy_from_slice(&mut self, i: u32, slice: &[u8]) { - self.obj = self - .env() - .bytes_copy_from_slice(self.to_object(), i.into(), slice) - .unwrap_optimized() - } - - /// Copy the bytes into the given slice. - /// - /// ### Panics - /// - /// If the output slice and bytes are of different lengths. - #[inline(always)] - pub fn copy_into_slice(&self, slice: &mut [u8]) { - let env = self.env(); - if self.len() as usize != slice.len() { - sdk_panic!("Bytes::copy_into_slice with mismatched slice length") - } - env.bytes_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) - .unwrap_optimized(); - } - - /// Returns a subset of the bytes as defined by the start and end bounds of - /// the range. - /// - /// ### Panics - /// - /// If the range is out-of-bounds. - #[must_use] - pub fn slice(&self, r: impl RangeBounds) -> Self { - let start_bound = match r.start_bound() { - Bound::Included(s) => *s, - Bound::Excluded(s) => s - .checked_add(1) - .expect_optimized("attempt to add with overflow"), - Bound::Unbounded => 0, - }; - let end_bound = match r.end_bound() { - Bound::Included(s) => s - .checked_add(1) - .expect_optimized("attempt to add with overflow"), - Bound::Excluded(s) => *s, - Bound::Unbounded => self.len(), - }; - let env = self.env(); - let bin = env - .bytes_slice(self.obj, start_bound.into(), end_bound.into()) - .unwrap_infallible(); - unsafe { Self::unchecked_new(env.clone(), bin) } - } - - pub fn iter(&self) -> BytesIter { - self.clone().into_iter() - } - - /// Copy the bytes into a buffer of given size. - /// - /// Returns the buffer and a range of where the bytes live in the given - /// buffer. - /// - /// Suitable when the size of the bytes isn't a fixed size but it is known - /// to be under a certain size, or failure due to overflow is acceptable. - /// - /// ### Panics - /// - /// If the size of the bytes is larger than the size of the buffer. To avoid - /// this, first slice the bytes into a smaller size then convert to a - /// buffer. - #[must_use] - pub fn to_buffer(&self) -> BytesBuffer { - let mut buffer = [0u8; B]; - let len = self.len() as usize; - { - let slice = &mut buffer[0..len]; - self.copy_into_slice(slice); - } - BytesBuffer { buffer, len } - } - - /// Copy the bytes into a Rust alloc Vec of size matching the bytes. - /// - /// Returns the Vec. Allocates using the built-in allocator. - /// - /// Suitable when the size of the bytes isn't a fixed size and the allocator - /// functionality of the sdk is enabled. - #[cfg(feature = "alloc")] - #[must_use] - pub fn to_alloc_vec(&self) -> alloc::vec::Vec { - let len = self.len() as usize; - let mut vec = alloc::vec::from_elem(0u8, len); - self.copy_into_slice(&mut vec); - vec - } - - /// Converts the contents of the Bytes into a respective String object. - /// - /// The conversion doesn't try to interpret the bytes as any particular - /// encoding, as the SDK `String` type doesn't assume any encoding either. - pub fn to_string(&self) -> String { - self.into() - } -} - -/// A `BytesBuffer` stores a variable number of bytes, up to a fixed limit `B`. -/// -/// The bytes are stored in a fixed-size non-heap-allocated structure. It is a -/// minimal wrapper around a fixed-size `[u8;B]` byte array and a length field -/// indicating the amount of the byte array containing meaningful data. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BytesBuffer { - buffer: [u8; B], - len: usize, -} - -impl Borrow<[u8]> for BytesBuffer { - /// Returns a borrow slice of the bytes stored in the BytesBuffer. - fn borrow(&self) -> &[u8] { - self.as_slice() - } -} - -impl BytesBuffer { - /// Returns a borrow slice of the bytes stored in the BytesBuffer. - pub fn as_slice(&self) -> &[u8] { - &self.buffer[..self.len] - } -} - -impl IntoIterator for Bytes { - type Item = u8; - type IntoIter = BytesIter; - - fn into_iter(self) -> Self::IntoIter { - BytesIter(self) - } -} - -#[derive(Clone)] -pub struct BytesIter(Bytes); - -impl BytesIter { - fn into_bin(self) -> Bytes { - self.0 - } -} - -impl Iterator for BytesIter { - type Item = u8; - - fn next(&mut self) -> Option { - if self.0.is_empty() { - None - } else { - let val: u32 = self - .0 - .env() - .bytes_front(self.0.obj) - .unwrap_infallible() - .into(); - self.0 = self.0.slice(1..); - Some(val as u8) - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.0.len() as usize; - (len, Some(len)) - } -} - -impl DoubleEndedIterator for BytesIter { - fn next_back(&mut self) -> Option { - let len = self.0.len(); - if len == 0 { - None - } else { - let val: u32 = self - .0 - .env() - .bytes_back(self.0.obj) - .unwrap_infallible() - .into(); - self.0 = self.0.slice(..len - 1); - Some(val as u8) - } - } -} - -impl FusedIterator for BytesIter {} - -impl ExactSizeIterator for BytesIter { - fn len(&self) -> usize { - self.0.len() as usize - } -} - -/// BytesN is a contiguous fixed-size array type containing `u8`s. -/// -/// The array is stored in the Host and available to the Guest through the -/// functions defined on Bytes. -/// -/// Bytes values can be stored as [Storage], or in other types like [Vec], [Map], -/// etc. -/// -/// ### Examples -/// -/// BytesN values can be created from arrays: -/// ``` -/// use soroban_sdk::{Bytes, BytesN, Env}; -/// -/// let env = Env::default(); -/// let bytes = BytesN::from_array(&env, &[0; 32]); -/// assert_eq!(bytes.len(), 32); -/// ``` -/// -/// BytesN and Bytes values are convertible: -/// ``` -/// use soroban_sdk::{Bytes, BytesN, Env}; -/// -/// let env = Env::default(); -/// let bytes = Bytes::from_slice(&env, &[0; 32]); -/// let bytes: BytesN<32> = bytes.try_into().expect("bytes to have length 32"); -/// assert_eq!(bytes.len(), 32); -/// ``` -#[derive(Clone)] -#[repr(transparent)] -pub struct BytesN(Bytes); - -impl Debug for BytesN { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "BytesN<{}>(", N)?; - let mut iter = self.iter(); - if let Some(x) = iter.next() { - write!(f, "{:?}", x)?; - } - for x in iter { - write!(f, ", {:?}", x)?; - } - write!(f, ")")?; - Ok(()) - } -} - -impl Eq for BytesN {} - -impl PartialEq for BytesN { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialEq<[u8; N]> for BytesN { - fn eq(&self, other: &[u8; N]) -> bool { - let other: BytesN = other.into_val(self.env()); - self.eq(&other) - } -} - -impl PartialEq> for [u8; N] { - fn eq(&self, other: &BytesN) -> bool { - let self_: BytesN = self.into_val(other.env()); - self_.eq(other) - } -} - -impl PartialOrd for BytesN { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl PartialOrd<[u8; N]> for BytesN { - fn partial_cmp(&self, other: &[u8; N]) -> Option { - let other: BytesN = other.into_val(self.env()); - self.partial_cmp(&other) - } -} - -impl PartialOrd> for [u8; N] { - fn partial_cmp(&self, other: &BytesN) -> Option { - let self_: BytesN = self.into_val(other.env()); - self_.partial_cmp(other) - } -} - -impl Ord for BytesN { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl Borrow for BytesN { - fn borrow(&self) -> &Bytes { - &self.0 - } -} - -impl Borrow for &BytesN { - fn borrow(&self) -> &Bytes { - &self.0 - } -} - -impl Borrow for &mut BytesN { - fn borrow(&self) -> &Bytes { - &self.0 - } -} - -impl AsRef for BytesN { - fn as_ref(&self) -> &Bytes { - &self.0 - } -} - -impl TryFromVal> for BytesN { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &BytesN) -> Result { - Ok(v.clone()) - } -} - -impl TryFromVal> for Bytes { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &BytesN) -> Result { - Ok(v.0.clone()) - } -} - -impl TryFromVal for BytesN { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &[u8; N]) -> Result { - Ok(BytesN::from_array(env, v)) - } -} - -impl TryFromVal> for [u8; N] { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &BytesN) -> Result { - Ok(v.to_array()) - } -} - -impl TryFromVal for BytesN { - type Error = ConversionError; - - fn try_from_val(env: &Env, obj: &BytesObject) -> Result { - Bytes::try_from_val(env, obj).unwrap_infallible().try_into() - } -} - -impl TryFromVal for BytesN { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Bytes::try_from_val(env, val)?.try_into() - } -} - -impl TryFromVal> for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &BytesN) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal> for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&BytesN) -> Result { - Ok(v.to_val()) - } -} - -impl TryFrom for BytesN { - type Error = ConversionError; - - #[inline(always)] - fn try_from(bin: Bytes) -> Result { - if bin.len() == { N as u32 } { - Ok(Self(bin)) - } else { - Err(ConversionError {}) - } - } -} - -impl TryFrom<&Bytes> for BytesN { - type Error = ConversionError; - - #[inline(always)] - fn try_from(bin: &Bytes) -> Result { - bin.clone().try_into() - } -} - -impl From> for Val { - #[inline(always)] - fn from(v: BytesN) -> Self { - v.0.into() - } -} - -impl From> for Bytes { - #[inline(always)] - fn from(v: BytesN) -> Self { - v.into_bytes() - } -} - -impl From<&BytesN> for Bytes { - #[inline(always)] - fn from(v: &BytesN) -> Self { - v.to_bytes() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&BytesN> for ScVal { - fn from(v: &BytesN) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.0.env, &v.0.obj.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From> for ScVal { - fn from(v: BytesN) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for BytesN { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Bytes::try_from_val(env, val)?.try_into() - } -} - -impl BytesN { - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: BytesObject) -> Self { - Self(Bytes::unchecked_new(env, obj)) - } - - pub fn env(&self) -> &Env { - self.0.env() - } - - pub fn as_bytes(&self) -> &Bytes { - &self.0 - } - - pub fn into_bytes(self) -> Bytes { - self.0 - } - - pub fn to_bytes(&self) -> Bytes { - self.0.clone() - } - - pub fn as_val(&self) -> &Val { - self.0.as_val() - } - - pub fn to_val(&self) -> Val { - self.0.to_val() - } - - pub fn as_object(&self) -> &BytesObject { - self.0.as_object() - } - - pub fn to_object(&self) -> BytesObject { - self.0.to_object() - } - - /// Create a BytesN from the slice. - #[inline(always)] - pub fn from_array(env: &Env, items: &[u8; N]) -> BytesN { - BytesN(Bytes::from_slice(env, items)) - } - - /// Sets the byte at the position with new value. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn set(&mut self, i: u32, v: u8) { - self.0.set(i, v); - } - - /// Returns the byte at the position or None if out-of-bounds. - #[inline(always)] - pub fn get(&self, i: u32) -> Option { - self.0.get(i) - } - - /// Returns the byte at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn get_unchecked(&self, i: u32) -> u8 { - self.0.get_unchecked(i) - } - - /// Returns true if the Bytes is empty and has a length of zero. - #[inline(always)] - pub fn is_empty(&self) -> bool { - N == 0 - } - - /// Returns the number of bytes are in the Bytes. - #[inline(always)] - pub fn len(&self) -> u32 { - N as u32 - } - - /// Returns the first byte or None if empty. - #[inline(always)] - pub fn first(&self) -> Option { - self.0.first() - } - - /// Returns the first byte. - /// - /// ### Panics - /// - /// If the Bytes is empty. - #[inline(always)] - pub fn first_unchecked(&self) -> u8 { - self.0.first_unchecked() - } - - /// Returns the last byte or None if empty. - #[inline(always)] - pub fn last(&self) -> Option { - self.0.last() - } - - /// Returns the last byte. - /// - /// ### Panics - /// - /// If the Bytes is empty. - #[inline(always)] - pub fn last_unchecked(&self) -> u8 { - self.0.last_unchecked() - } - - /// Copy the bytes into the given slice. - #[inline(always)] - pub fn copy_into_slice(&self, slice: &mut [u8; N]) { - let env = self.env(); - env.bytes_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) - .unwrap_optimized(); - } - - /// Copy the bytes in [BytesN] into an array. - #[inline(always)] - pub fn to_array(&self) -> [u8; N] { - let mut array = [0u8; N]; - self.copy_into_slice(&mut array); - array - } - - pub fn iter(&self) -> BytesIter { - self.clone().into_iter() - } -} - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl crate::testutils::BytesN for BytesN { - fn random(env: &Env) -> BytesN { - BytesN::from_array(env, &crate::testutils::random()) - } -} - -impl IntoIterator for BytesN { - type Item = u8; - - type IntoIter = BytesIter; - - fn into_iter(self) -> Self::IntoIter { - BytesIter(self.0) - } -} - -impl TryFrom for [u8; N] { - type Error = ConversionError; - - fn try_from(bin: Bytes) -> Result { - let fixed: BytesN = bin.try_into()?; - Ok(fixed.into()) - } -} - -impl TryFrom<&Bytes> for [u8; N] { - type Error = ConversionError; - - fn try_from(bin: &Bytes) -> Result { - let fixed: BytesN = bin.try_into()?; - Ok(fixed.into()) - } -} - -impl From> for [u8; N] { - fn from(bin: BytesN) -> Self { - let mut res = [0u8; N]; - for (i, b) in bin.into_iter().enumerate() { - res[i] = b; - } - res - } -} - -impl From<&BytesN> for [u8; N] { - fn from(bin: &BytesN) -> Self { - let mut res = [0u8; N]; - for (i, b) in bin.iter().enumerate() { - res[i] = b; - } - res - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn bytes_from_and_to_slices() { - let env = Env::default(); - - let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); - let mut out = [0u8; 4]; - b.copy_into_slice(&mut out); - assert_eq!([1, 2, 3, 4], out); - - let mut b = Bytes::from_slice(&env, &[1, 2, 3, 4]); - b.extend_from_slice(&[5, 6, 7, 8]); - b.insert_from_slice(1, &[9, 10]); - b.insert_from_bytes(4, Bytes::from_slice(&env, &[0, 0])); - let mut out = [0u8; 12]; - b.copy_into_slice(&mut out); - assert_eq!([1, 9, 10, 2, 0, 0, 3, 4, 5, 6, 7, 8], out); - b.copy_from_slice(3, &[7, 6, 5]); - b.copy_into_slice(&mut out); - assert_eq!([1, 9, 10, 7, 6, 5, 3, 4, 5, 6, 7, 8], out); - } - - #[test] - fn bytesn_from_and_to_slices() { - let env = Env::default(); - - let b = BytesN::from_array(&env, &[1, 2, 3, 4]); - let mut out = [0u8; 4]; - b.copy_into_slice(&mut out); - assert_eq!([1, 2, 3, 4], out); - } - - #[test] - #[should_panic] - fn bytes_to_short_slice() { - let env = Env::default(); - let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); - let mut out = [0u8; 3]; - b.copy_into_slice(&mut out); - } - - #[test] - #[should_panic] - fn bytes_to_long_slice() { - let env = Env::default(); - let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); - let mut out = [0u8; 5]; - b.copy_into_slice(&mut out); - } - - #[test] - fn macro_bytes() { - let env = Env::default(); - assert_eq!(bytes!(&env), Bytes::new(&env)); - assert_eq!(bytes!(&env, 1), { - let mut b = Bytes::new(&env); - b.push_back(1); - b - }); - assert_eq!(bytes!(&env, 1,), { - let mut b = Bytes::new(&env); - b.push_back(1); - b - }); - assert_eq!(bytes!(&env, [3, 2, 1,]), { - let mut b = Bytes::new(&env); - b.push_back(3); - b.push_back(2); - b.push_back(1); - b - }); - } - - #[test] - fn macro_bytes_hex() { - let env = Env::default(); - assert_eq!(bytes!(&env), Bytes::new(&env)); - assert_eq!(bytes!(&env, 1), { - let mut b = Bytes::new(&env); - b.push_back(1); - b - }); - assert_eq!(bytes!(&env, 1,), { - let mut b = Bytes::new(&env); - b.push_back(1); - b - }); - assert_eq!(bytes!(&env, 0x30201), { - let mut b = Bytes::new(&env); - b.push_back(3); - b.push_back(2); - b.push_back(1); - b - }); - assert_eq!(bytes!(&env, 0x0000030201), { - Bytes::from_array(&env, &[0, 0, 3, 2, 1]) - }); - } - - #[test] - fn macro_bytesn() { - let env = Env::default(); - assert_eq!(bytesn!(&env, 1), { BytesN::from_array(&env, &[1]) }); - assert_eq!(bytesn!(&env, 1,), { BytesN::from_array(&env, &[1]) }); - assert_eq!(bytesn!(&env, [3, 2, 1,]), { - BytesN::from_array(&env, &[3, 2, 1]) - }); - } - - #[test] - fn macro_bytesn_hex() { - let env = Env::default(); - assert_eq!(bytesn!(&env, 0x030201), { - BytesN::from_array(&env, &[3, 2, 1]) - }); - assert_eq!(bytesn!(&env, 0x0000030201), { - BytesN::from_array(&env, &[0, 0, 3, 2, 1]) - }); - } - - #[test] - fn test_bin() { - let env = Env::default(); - - let mut bin = Bytes::new(&env); - assert_eq!(bin.len(), 0); - bin.push_back(10); - assert_eq!(bin.len(), 1); - bin.push_back(20); - assert_eq!(bin.len(), 2); - bin.push_back(30); - assert_eq!(bin.len(), 3); - println!("{:?}", bin); - - let bin_ref = &bin; - assert_eq!(bin_ref.len(), 3); - - let mut bin_copy = bin.clone(); - assert!(bin == bin_copy); - assert_eq!(bin_copy.len(), 3); - bin_copy.push_back(40); - assert_eq!(bin_copy.len(), 4); - assert!(bin != bin_copy); - - assert_eq!(bin.len(), 3); - assert_eq!(bin_ref.len(), 3); - - bin_copy.pop_back(); - assert!(bin == bin_copy); - - let bad_fixed: Result, ConversionError> = bin.try_into(); - assert!(bad_fixed.is_err()); - let fixed: BytesN<3> = bin_copy.try_into().unwrap(); - println!("{:?}", fixed); - } - - #[test] - fn test_bin_iter() { - let env = Env::default(); - let mut bin = Bytes::new(&env); - bin.push_back(10); - bin.push_back(20); - bin.push_back(30); - let mut iter = bin.iter(); - assert_eq!(iter.next(), Some(10)); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.next(), Some(30)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - let mut iter = bin.iter(); - assert_eq!(iter.next(), Some(10)); - assert_eq!(iter.next_back(), Some(30)); - assert_eq!(iter.next_back(), Some(20)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - - let fixed: BytesN<3> = bin.try_into().unwrap(); - let mut iter = fixed.iter(); - assert_eq!(iter.next(), Some(10)); - assert_eq!(iter.next(), Some(20)); - assert_eq!(iter.next(), Some(30)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - let mut iter = fixed.iter(); - assert_eq!(iter.next(), Some(10)); - assert_eq!(iter.next_back(), Some(30)); - assert_eq!(iter.next_back(), Some(20)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - } - - #[test] - fn test_array_binary_borrow() { - fn get_len(b: impl Borrow) -> u32 { - let b: &Bytes = b.borrow(); - b.len() - } - - let env = Env::default(); - let mut bin = Bytes::new(&env); - bin.push_back(10); - bin.push_back(20); - bin.push_back(30); - assert_eq!(bin.len(), 3); - - let arr_bin: BytesN<3> = bin.clone().try_into().unwrap(); - assert_eq!(arr_bin.len(), 3); - - assert_eq!(get_len(&bin), 3); - assert_eq!(get_len(bin), 3); - assert_eq!(get_len(&arr_bin), 3); - assert_eq!(get_len(arr_bin), 3); - } - - #[test] - fn bytesn_debug() { - let env = Env::default(); - let mut bin = Bytes::new(&env); - bin.push_back(10); - bin.push_back(20); - bin.push_back(30); - let arr_bin: BytesN<3> = bin.clone().try_into().unwrap(); - assert_eq!(format!("{:?}", arr_bin), "BytesN<3>(10, 20, 30)"); - } - - #[test] - fn test_is_empty() { - let env = Env::default(); - let mut bin = Bytes::new(&env); - assert_eq!(bin.is_empty(), true); - bin.push_back(10); - assert_eq!(bin.is_empty(), false); - } - - #[test] - fn test_first() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - - assert_eq!(bin.first(), Some(1)); - bin.remove(0); - assert_eq!(bin.first(), Some(2)); - - // first on empty bytes - let bin = bytes![&env]; - assert_eq!(bin.first(), None); - } - - #[test] - fn test_first_unchecked() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - - assert_eq!(bin.first_unchecked(), 1); - bin.remove(0); - assert_eq!(bin.first_unchecked(), 2); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_first_unchecked_panics() { - let env = Env::default(); - let bin = bytes![&env]; - bin.first_unchecked(); - } - - #[test] - fn test_last() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - - assert_eq!(bin.last(), Some(4)); - bin.remove(3); - assert_eq!(bin.last(), Some(3)); - - // last on empty bytes - let bin = bytes![&env]; - assert_eq!(bin.last(), None); - } - - #[test] - fn test_last_unchecked() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - - assert_eq!(bin.last_unchecked(), 4); - bin.remove(3); - assert_eq!(bin.last_unchecked(), 3); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_last_unchecked_panics() { - let env = Env::default(); - let bin = bytes![&env]; - bin.last_unchecked(); - } - - #[test] - fn test_get() { - let env = Env::default(); - let bin = bytes![&env, [0, 1, 5, 2, 8]]; - - assert_eq!(bin.get(0), Some(0)); - assert_eq!(bin.get(1), Some(1)); - assert_eq!(bin.get(2), Some(5)); - assert_eq!(bin.get(3), Some(2)); - assert_eq!(bin.get(4), Some(8)); - - assert_eq!(bin.get(bin.len()), None); - assert_eq!(bin.get(bin.len() + 1), None); - assert_eq!(bin.get(u32::MAX), None); - - // tests on an empty vec - let bin = bytes![&env]; - assert_eq!(bin.get(0), None); - assert_eq!(bin.get(bin.len()), None); - assert_eq!(bin.get(bin.len() + 1), None); - assert_eq!(bin.get(u32::MAX), None); - } - - #[test] - fn test_get_unchecked() { - let env = Env::default(); - let bin = bytes![&env, [0, 1, 5, 2, 8]]; - - assert_eq!(bin.get_unchecked(0), 0); - assert_eq!(bin.get_unchecked(1), 1); - assert_eq!(bin.get_unchecked(2), 5); - assert_eq!(bin.get_unchecked(3), 2); - assert_eq!(bin.get_unchecked(4), 8); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_get_unchecked_panics() { - let env = Env::default(); - let bin = bytes![&env]; - bin.get_unchecked(0); - } - - #[test] - fn test_remove() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - - assert_eq!(bin.remove(2), Some(())); - assert_eq!(bin, bytes![&env, [1, 2, 4]]); - assert_eq!(bin.len(), 3); - - // out of bound removes - assert_eq!(bin.remove(bin.len()), None); - assert_eq!(bin.remove(bin.len() + 1), None); - assert_eq!(bin.remove(u32::MAX), None); - - // remove rest of items - assert_eq!(bin.remove(0), Some(())); - assert_eq!(bin.remove(0), Some(())); - assert_eq!(bin.remove(0), Some(())); - assert_eq!(bin, bytes![&env]); - assert_eq!(bin.len(), 0); - - // try remove from empty bytes - let mut bin = bytes![&env]; - assert_eq!(bin.remove(0), None); - assert_eq!(bin.remove(bin.len()), None); - assert_eq!(bin.remove(bin.len() + 1), None); - assert_eq!(bin.remove(u32::MAX), None); - } - - #[test] - fn test_remove_unchecked() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - - bin.remove_unchecked(2); - assert_eq!(bin, bytes![&env, [1, 2, 4]]); - assert_eq!(bin.len(), 3); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_remove_unchecked_panics() { - let env = Env::default(); - let mut bin = bytes![&env, [1, 2, 3, 4]]; - bin.remove_unchecked(bin.len()); - } - - #[test] - fn test_pop() { - let env = Env::default(); - let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; - - assert_eq!(bin.pop_back(), Some(4)); - assert_eq!(bin.pop_back(), Some(3)); - assert_eq!(bin.len(), 3); - assert_eq!(bin, bytes![&env, [0, 1, 2]]); - - // pop on empty bytes - let mut bin = bytes![&env]; - assert_eq!(bin.pop_back(), None); - } - - #[test] - fn test_pop_unchecked() { - let env = Env::default(); - let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; - - assert_eq!(bin.pop_back_unchecked(), 4); - assert_eq!(bin.pop_back_unchecked(), 3); - assert_eq!(bin.len(), 3); - assert_eq!(bin, bytes![&env, [0, 1, 2]]); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_pop_unchecked_panics() { - let env = Env::default(); - let mut bin = bytes![&env]; - bin.pop_back_unchecked(); - } - - #[test] - fn test_insert() { - let env = Env::default(); - let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; - - bin.insert(3, 42); - assert_eq!(bin, bytes![&env, [0, 1, 2, 42, 3, 4]]); - - // insert at start - bin.insert(0, 43); - assert_eq!(bin, bytes![&env, [43, 0, 1, 2, 42, 3, 4]]); - - // insert at end - bin.insert(bin.len(), 44); - assert_eq!(bin, bytes![&env, [43, 0, 1, 2, 42, 3, 4, 44]]); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_insert_panic() { - let env = Env::default(); - let mut bin = bytes![&env, [0, 1, 2, 3, 4]]; - bin.insert(80, 44); - } - - #[test] - fn test_slice() { - let env = Env::default(); - let bin = bytes![&env, [0, 1, 2, 3, 4]]; - - let bin2 = bin.slice(2..); - assert_eq!(bin2, bytes![&env, [2, 3, 4]]); - - let bin3 = bin.slice(3..3); - assert_eq!(bin3, bytes![&env]); - - let bin4 = bin.slice(0..3); - assert_eq!(bin4, bytes![&env, [0, 1, 2]]); - - let bin4 = bin.slice(3..5); - assert_eq!(bin4, bytes![&env, [3, 4]]); - - assert_eq!(bin, bytes![&env, [0, 1, 2, 3, 4]]); // makes sure original bytes is unchanged - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_slice_panic() { - let env = Env::default(); - let bin = bytes![&env, [0, 1, 2, 3, 4]]; - let _ = bin.slice(..=bin.len()); - } - - #[test] - fn test_bytes_to_string() { - let env = Env::default(); - let b: Bytes = bytes![&env, [0, 1, 2, 3, 4]]; - let s: String = b.clone().into(); - assert_eq!(s.len(), 5); - let mut slice = [0u8; 5]; - s.copy_into_slice(&mut slice); - assert_eq!(slice, [0, 1, 2, 3, 4]); - let s2 = b.to_string(); - assert_eq!(s, s2); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs b/temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs deleted file mode 100644 index e493594..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/constructor_args.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::{Env, IntoVal, Val, Vec}; - -pub trait ConstructorArgs: IntoVal> {} - -impl ConstructorArgs for Vec {} - -macro_rules! impl_constructor_args_for_tuple { - ( $($typ:ident $idx:tt)* ) => { - impl<$($typ),*> ConstructorArgs for ($($typ,)*) - where - $($typ: IntoVal),* - { - } - }; -} - -// 0 topics -impl ConstructorArgs for () {} -// 1-13 topics -impl_constructor_args_for_tuple! { T0 0 } -impl_constructor_args_for_tuple! { T0 0 T1 1 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 } -impl_constructor_args_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 } diff --git a/temp_sdk/soroban-sdk-26.0.1/src/crypto.rs b/temp_sdk/soroban-sdk-26.0.1/src/crypto.rs deleted file mode 100644 index daec7d5..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/crypto.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! Crypto contains functions for cryptographic functions. - -use crate::{ - env::internal::{self, BytesObject}, - unwrap::UnwrapInfallible, - Bytes, BytesN, ConversionError, Env, IntoVal, Symbol, TryFromVal, TryIntoVal, Val, Vec, U256, -}; - -pub mod bls12_381; -pub mod bn254; -pub(crate) mod utils; -/// Deprecated alias for `bn254::Bn254Fr`. -/// Use `bn254::Bn254Fr` directly instead. -#[deprecated(note = "use `bn254::Bn254Fr` instead")] -pub use bn254::Bn254Fr as BnScalar; - -/// A `BytesN` intended to contain the output of a cryptographic hash -/// function. -/// -/// When a `Hash` is returned by [`sha256`][Crypto::sha256] or -/// [`keccak256`][Crypto::keccak256], the SDK guarantees that the bytes came -/// from the corresponding secure cryptographic hash function. The host also -/// provides this guarantee for the first parameter of -/// [`CustomAccountInterface::__check_auth`][crate::auth::CustomAccountInterface::__check_auth]. -/// -/// `Hash` is represented at contract boundaries as `BytesN`, so accepting -/// it as a general contract entrypoint argument does not prove that the caller -/// supplied bytes were produced by a secure cryptographic hash function. Use -/// `BytesN` for externally supplied digests. -/// -/// **__Note:_** A Hash should not be used with storage, since no guarantee can -/// be made about the Bytes stored as to whether they were in fact from a secure -/// cryptographic hash function. -#[derive(Clone)] -#[repr(transparent)] -pub struct Hash(BytesN); - -impl Hash { - /// Constructs a new `Hash` from a fixed-length bytes array. - /// - /// This is intended for test-only, since `Hash` type is only meant to be - /// constructed via secure manners. - #[cfg(test)] - pub(crate) fn from_bytes(bytes: BytesN) -> Self { - Self(bytes) - } - - /// Returns a [`BytesN`] containing the bytes in this hash. - #[inline(always)] - pub fn to_bytes(&self) -> BytesN { - self.0.clone() - } - - /// Returns an array containing the bytes in this hash. - #[inline(always)] - pub fn to_array(&self) -> [u8; N] { - self.0.to_array() - } - - pub fn as_val(&self) -> &Val { - self.0.as_val() - } - - pub fn to_val(&self) -> Val { - self.0.to_val() - } - - pub fn as_object(&self) -> &BytesObject { - self.0.as_object() - } - - pub fn to_object(&self) -> BytesObject { - self.0.to_object() - } -} - -impl IntoVal for Hash { - fn into_val(&self, e: &Env) -> Val { - self.0.into_val(e) - } -} - -impl IntoVal> for Hash { - fn into_val(&self, _e: &Env) -> BytesN { - self.0.clone() - } -} - -impl From> for Bytes { - fn from(v: Hash) -> Self { - v.0.into() - } -} - -impl From> for BytesN { - fn from(v: Hash) -> Self { - v.0 - } -} - -impl Into<[u8; N]> for Hash { - fn into(self) -> [u8; N] { - self.0.into() - } -} - -#[allow(deprecated)] -impl crate::TryFromValForContractFn for Hash { - type Error = ConversionError; - - fn try_from_val_for_contract_fn(env: &Env, v: &Val) -> Result { - Ok(Hash(BytesN::::try_from_val(env, v)?)) - } -} - -/// Crypto provides access to cryptographic functions. -pub struct Crypto { - env: Env, -} - -impl Crypto { - pub(crate) fn new(env: &Env) -> Crypto { - Crypto { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - /// Returns the SHA-256 hash of the data. - pub fn sha256(&self, data: &Bytes) -> Hash<32> { - let env = self.env(); - let bin = internal::Env::compute_hash_sha256(env, data.into()).unwrap_infallible(); - unsafe { Hash(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Returns the Keccak-256 hash of the data. - pub fn keccak256(&self, data: &Bytes) -> Hash<32> { - let env = self.env(); - let bin = internal::Env::compute_hash_keccak256(env, data.into()).unwrap_infallible(); - unsafe { Hash(BytesN::unchecked_new(env.clone(), bin)) } - } - - /// Verifies an ed25519 signature. - /// - /// The signature is verified as a valid signature of the message by the - /// ed25519 public key. - /// - /// ### Panics - /// - /// If the signature verification fails. - pub fn ed25519_verify(&self, public_key: &BytesN<32>, message: &Bytes, signature: &BytesN<64>) { - let env = self.env(); - let _ = internal::Env::verify_sig_ed25519( - env, - public_key.to_object(), - message.to_object(), - signature.to_object(), - ); - } - - /// Recovers the ECDSA secp256k1 public key. - /// - /// The public key returned is the SEC-1-encoded ECDSA secp256k1 public key - /// that produced the 64-byte signature over a given 32-byte message digest, - /// for a given recovery_id byte. - pub fn secp256k1_recover( - &self, - message_digest: &Hash<32>, - signature: &BytesN<64>, - recovery_id: u32, - ) -> BytesN<65> { - let env = self.env(); - CryptoHazmat::new(env).secp256k1_recover(&message_digest.0, signature, recovery_id) - } - - /// Verifies the ECDSA secp256r1 signature. - /// - /// The SEC-1-encoded public key is provided along with the message, - /// verifies the 64-byte signature. - pub fn secp256r1_verify( - &self, - public_key: &BytesN<65>, - message_digest: &Hash<32>, - signature: &BytesN<64>, - ) { - let env = self.env(); - CryptoHazmat::new(env).secp256r1_verify(public_key, &message_digest.0, signature) - } - - /// Get a [Bls12_381][bls12_381::Bls12_381] for accessing the bls12-381 - /// functions. - pub fn bls12_381(&self) -> bls12_381::Bls12_381 { - bls12_381::Bls12_381::new(self.env()) - } - - /// Get a [Bn254][bn254::Bn254] for accessing the bn254 - /// functions. - pub fn bn254(&self) -> bn254::Bn254 { - bn254::Bn254::new(self.env()) - } -} - -/// # ⚠️ Hazardous Materials -/// -/// Cryptographic functions under [CryptoHazmat] are low-leveled which can be -/// insecure if misused. They are not generally recommended. Using them -/// incorrectly can introduce security vulnerabilities. Please use [Crypto] if -/// possible. -#[cfg_attr(any(test, feature = "hazmat-crypto"), visibility::make(pub))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-crypto")))] -pub(crate) struct CryptoHazmat { - env: Env, -} - -impl CryptoHazmat { - pub(crate) fn new(env: &Env) -> CryptoHazmat { - CryptoHazmat { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - /// Recovers the ECDSA secp256k1 public key. - /// - /// The public key returned is the SEC-1-encoded ECDSA secp256k1 public key - /// that produced the 64-byte signature over a given 32-byte message digest, - /// for a given recovery_id byte. - /// - /// WARNING: The `message_digest` must be produced by a secure cryptographic - /// hash function on the message, otherwise the attacker can potentially - /// forge signatures. - pub fn secp256k1_recover( - &self, - message_digest: &BytesN<32>, - signature: &BytesN<64>, - recovery_id: u32, - ) -> BytesN<65> { - let env = self.env(); - let bytes = internal::Env::recover_key_ecdsa_secp256k1( - env, - message_digest.to_object(), - signature.to_object(), - recovery_id.into(), - ) - .unwrap_infallible(); - unsafe { BytesN::unchecked_new(env.clone(), bytes) } - } - - /// Verifies the ECDSA secp256r1 signature. - /// - /// The SEC-1-encoded public key is provided along with a 32-byte message - /// digest, verifies the 64-byte signature. - /// - /// WARNING: The `message_digest` must be produced by a secure cryptographic - /// hash function on the message, otherwise the attacker can potentially - /// forge signatures. - pub fn secp256r1_verify( - &self, - public_key: &BytesN<65>, - message_digest: &BytesN<32>, - signature: &BytesN<64>, - ) { - let env = self.env(); - let _ = internal::Env::verify_sig_ecdsa_secp256r1( - env, - public_key.to_object(), - message_digest.to_object(), - signature.to_object(), - ) - .unwrap_infallible(); - } - - /// Performs a Poseidon permutation on the input state vector. - /// - /// This is a **low-level** permutation primitive. For safe, user-friendly - /// hash functions, use - /// [`rs-soroban-poseidon`](https://github.com/stellar/rs-soroban-poseidon) - /// instead, which provides input validation and standard hash constructions. - /// - /// # Field elements and `U256` - /// - /// All `U256` values (`input`, `mds`, `round_constants`) are generic - /// representations of field elements in the prime field specified by - /// `field`. If a `U256` value exceeds the field modulus, it is **silently - /// reduced mod the field order**. Two distinct `U256` inputs that reduce - /// to the same field element will produce the same output, leading to - /// unintended collisions. Callers must ensure inputs are already in the - /// valid field range. - /// - /// # Parameters - /// - /// - `input`: state vector of `t` field elements. - /// - `field`: the prime field (`"BLS12_381"` or `"BN254"`). - /// - `t`: state size (number of field elements). - /// - `d`: S-box degree (5 for BLS12-381 and BN254). - /// - `rounds_f`: number of full rounds (must be even). - /// - `rounds_p`: number of partial rounds. - /// - `mds`: `t`-by-`t` MDS matrix as `Vec>`. - /// - `round_constants`: `(rounds_f + rounds_p)`-by-`t` matrix of round - /// constants as `Vec>`. - /// - /// # Panics - /// - /// If any dimension is inconsistent or if `field` is unsupported. - pub fn poseidon_permutation( - &self, - input: &Vec, - field: Symbol, - t: u32, - d: u32, - rounds_f: u32, - rounds_p: u32, - mds: &Vec>, - round_constants: &Vec>, - ) -> Vec { - let env = self.env(); - let result = internal::Env::poseidon_permutation( - env, - input.to_object(), - field.to_symbol_val(), - t.into(), - d.into(), - rounds_f.into(), - rounds_p.into(), - mds.to_object(), - round_constants.to_object(), - ) - .unwrap_infallible(); - - result.try_into_val(env).unwrap_infallible() - } - - /// Performs a Poseidon2 permutation on the input state vector. - /// - /// This is a **low-level** permutation primitive. For safe, user-friendly - /// hash functions, use - /// [`rs-soroban-poseidon`](https://github.com/stellar/rs-soroban-poseidon) - /// instead, which provides input validation and standard hash constructions. - /// - /// # Field elements and `U256` - /// - /// All `U256` values (`input`, `mat_internal_diag_m_1`, `round_constants`) - /// are generic representations of field elements in the prime field - /// specified by `field`. If a `U256` value exceeds the field modulus, it - /// is **silently reduced mod the field order**. Two distinct `U256` inputs - /// that reduce to the same field element will produce the same output, - /// leading to unintended collisions. Callers must ensure inputs are - /// already in the valid field range. - /// - /// # Parameters - /// - /// - `input`: state vector of `t` field elements. - /// - `field`: the prime field (`"BLS12_381"` or `"BN254"`). - /// - `t`: state size (number of field elements). Only - /// `t` ∈ {2, 3, 4, 8, 12, 16, 20, 24} are supported. - /// - `d`: S-box degree (5 for BLS12-381 and BN254). - /// - `rounds_f`: number of full rounds (must be even). - /// - `rounds_p`: number of partial rounds. - /// - `mat_internal_diag_m_1`: diagonal of the internal matrix minus the - /// identity, as `Vec` of length `t`. - /// - `round_constants`: `(rounds_f + rounds_p)`-by-`t` matrix of round - /// constants as `Vec>`. - /// - /// # Panics - /// - /// If any dimension is inconsistent or if `field` is unsupported. - pub fn poseidon2_permutation( - &self, - input: &Vec, - field: Symbol, - t: u32, - d: u32, - rounds_f: u32, - rounds_p: u32, - mat_internal_diag_m_1: &Vec, - round_constants: &Vec>, - ) -> Vec { - let env = self.env(); - let result = internal::Env::poseidon2_permutation( - env, - input.to_object(), - field.to_symbol_val(), - t.into(), - d.into(), - rounds_f.into(), - rounds_p.into(), - mat_internal_diag_m_1.to_object(), - round_constants.to_object(), - ) - .unwrap_infallible(); - - result.try_into_val(env).unwrap_infallible() - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/deploy.rs b/temp_sdk/soroban-sdk-26.0.1/src/deploy.rs deleted file mode 100644 index 689e8e6..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/deploy.rs +++ /dev/null @@ -1,469 +0,0 @@ -//! Deploy contains types for deploying contracts. -//! -//! Contracts are assigned an ID that is derived from a set of arguments. A -//! contract may choose which set of arguments to use to deploy with: -//! -//! - [Deployer::with_current_contract] – A contract deployed by the currently -//! executing contract will have an ID derived from the currently executing -//! contract's ID. -//! -//! The deployer can be created using [Env::deployer]. -//! -//! ### Examples -//! -//! #### Deploy a contract without constructor (or 0-argument constructor) -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol}; -//! -//! const DEPLOYED_WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn deploy(env: Env, wasm_hash: BytesN<32>) { -//! let salt = [0u8; 32]; -//! let deployer = env.deployer().with_current_contract(salt); -//! let contract_address = deployer.deploy_v2(wasm_hash, ()); -//! // ... -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let contract_address = env.register(Contract, ()); -//! let contract = ContractClient::new(&env, &contract_address); -//! // Upload the contract code before deploying its instance. -//! let wasm_hash = env.deployer().upload_contract_wasm(DEPLOYED_WASM); -//! contract.deploy(&wasm_hash); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! #### Deploy a contract with a multi-argument constructor -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol, IntoVal}; -//! -//! const DEPLOYED_WASM_WITH_CTOR: &[u8] = include_bytes!("../doctest_fixtures/contract_with_constructor.wasm"); -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn deploy_with_constructor(env: Env, wasm_hash: BytesN<32>) { -//! let salt = [1u8; 32]; -//! let deployer = env.deployer().with_current_contract(salt); -//! let contract_address = deployer.deploy_v2( -//! wasm_hash, -//! (1_u32, 2_i64), -//! ); -//! // ... -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let contract_address = env.register(Contract, ()); -//! let contract = ContractClient::new(&env, &contract_address); -//! // Upload the contract code before deploying its instance. -//! let wasm_hash = env.deployer().upload_contract_wasm(DEPLOYED_WASM_WITH_CTOR); -//! contract.deploy_with_constructor(&wasm_hash); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! #### Derive before deployment what the address of a contract will be -//! -//! ``` -//! use soroban_sdk::{contract, contractimpl, Address, BytesN, Env, Symbol, IntoVal}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn deploy_contract_address(env: Env) -> Address { -//! let salt = [1u8; 32]; -//! let deployer = env.deployer().with_current_contract(salt); -//! // Deployed contract address is deterministic and can be accessed -//! // before deploying the contract. It is derived from the deployer -//! // (the current contract's address) and the salt passed in above. -//! deployer.deployed_address() -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let contract_address = env.register(Contract, ()); -//! let contract = ContractClient::new(&env, &contract_address); -//! assert_eq!( -//! contract.deploy_contract_address(), -//! Address::from_str(&env, "CBESJIMX7J53SWJGJ7WQ6QTLJI4S5LPPJNC2BNVD63GIKAYCDTDOO322"), -//! ); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` - -use crate::{ - env::internal::{ContractTtlExtension, Env as _}, - unwrap::UnwrapInfallible, - Address, Bytes, BytesN, ConstructorArgs, Env, IntoVal, -}; - -/// Deployer provides access to deploying contracts. -pub struct Deployer { - env: Env, -} - -impl Deployer { - pub(crate) fn new(env: &Env) -> Deployer { - Deployer { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - /// Get a deployer that deploys contract that derive the contract IDs - /// from the current contract and provided salt. - pub fn with_current_contract( - &self, - salt: impl IntoVal>, - ) -> DeployerWithAddress { - DeployerWithAddress { - env: self.env.clone(), - address: self.env.current_contract_address(), - salt: salt.into_val(&self.env), - } - } - - /// Get a deployer that deploys contracts that derive the contract ID - /// from the provided address and salt. - /// - /// The deployer address must authorize all the deployments. - pub fn with_address( - &self, - address: Address, - salt: impl IntoVal>, - ) -> DeployerWithAddress { - DeployerWithAddress { - env: self.env.clone(), - address, - salt: salt.into_val(&self.env), - } - } - - /// Get a deployer that deploys an instance of Stellar Asset Contract - /// corresponding to the provided serialized asset. - /// - /// `serialized_asset` is the Stellar `Asset` XDR serialized to bytes. Refer - /// to `[soroban_sdk::xdr::Asset]` - pub fn with_stellar_asset( - &self, - serialized_asset: impl IntoVal, - ) -> DeployerWithAsset { - DeployerWithAsset { - env: self.env.clone(), - serialized_asset: serialized_asset.into_val(&self.env), - } - } - - /// Upload the contract Wasm code to the network. - /// - /// Returns the hash of the uploaded Wasm that can be then used for - /// the contract deployment. - /// ### Examples - /// ``` - /// use soroban_sdk::{BytesN, Env}; - /// - /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// env.deployer().upload_contract_wasm(WASM); - /// } - /// ``` - pub fn upload_contract_wasm(&self, contract_wasm: impl IntoVal) -> BytesN<32> { - self.env - .upload_wasm(contract_wasm.into_val(&self.env).to_object()) - .unwrap_infallible() - .into_val(&self.env) - } - - /// Replaces the executable of the current contract with the provided Wasm. - /// - /// The Wasm blob identified by the `wasm_hash` has to be already present - /// in the ledger (uploaded via `[Deployer::upload_contract_wasm]`). - /// - /// The function won't do anything immediately. The contract executable - /// will only be updated after the invocation has successfully finished. - pub fn update_current_contract_wasm(&self, wasm_hash: impl IntoVal>) { - self.env - .update_current_contract_wasm(wasm_hash.into_val(&self.env).to_object()) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract instance and code. - /// - /// Extends the TTL of the instance and code only if the TTL for the provided contract is below `threshold` ledgers. - /// The TTL will then become `extend_to`. Note that the `threshold` check and TTL extensions are done for both the - /// contract code and contract instance, so it's possible that one is bumped but not the other depending on what the - /// current TTL's are. - /// - /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. - pub fn extend_ttl(&self, contract_address: Address, threshold: u32, extend_to: u32) { - self.env - .extend_contract_instance_and_code_ttl( - contract_address.to_object(), - threshold.into(), - extend_to.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract instance. - /// - /// Same as [`extend_ttl`](Self::extend_ttl) but only for contract instance. - pub fn extend_ttl_for_contract_instance( - &self, - contract_address: Address, - threshold: u32, - extend_to: u32, - ) { - self.env - .extend_contract_instance_ttl( - contract_address.to_object(), - threshold.into(), - extend_to.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract code. - /// - /// Same as [`extend_ttl`](Self::extend_ttl) but only for contract code. - pub fn extend_ttl_for_code(&self, contract_address: Address, threshold: u32, extend_to: u32) { - self.env - .extend_contract_code_ttl( - contract_address.to_object(), - threshold.into(), - extend_to.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract instance and code with limits on the extension. - /// - /// Extends the TTL of the instance and code to be up to `extend_to` ledgers. - /// The extension only happens if it exceeds `min_extension` ledgers, otherwise - /// this is a no-op. The amount of extension will not exceed `max_extension` ledgers. - /// - /// Note that the extension is applied to both the contract code and contract instance, - /// so it's possible that one is extended but not the other depending on their current TTLs. - /// - /// The TTL is the number of ledgers between the current ledger and the final ledger - /// the data can still be accessed. - pub fn extend_ttl_with_limits( - &self, - contract_address: Address, - extend_to: u32, - min_extension: u32, - max_extension: u32, - ) { - self.env - .extend_contract_instance_and_code_ttl_v2( - contract_address.to_object(), - ContractTtlExtension::InstanceAndCode, - extend_to.into(), - min_extension.into(), - max_extension.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract instance with limits on the extension. - /// - /// Same as [`extend_ttl_with_limits`](Self::extend_ttl_with_limits) but only for contract instance. - pub fn extend_ttl_for_contract_instance_with_limits( - &self, - contract_address: Address, - extend_to: u32, - min_extension: u32, - max_extension: u32, - ) { - self.env - .extend_contract_instance_and_code_ttl_v2( - contract_address.to_object(), - ContractTtlExtension::Instance, - extend_to.into(), - min_extension.into(), - max_extension.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract code with limits on the extension. - /// - /// Same as [`extend_ttl_with_limits`](Self::extend_ttl_with_limits) but only for contract code. - pub fn extend_ttl_for_code_with_limits( - &self, - contract_address: Address, - extend_to: u32, - min_extension: u32, - max_extension: u32, - ) { - self.env - .extend_contract_instance_and_code_ttl_v2( - contract_address.to_object(), - ContractTtlExtension::Code, - extend_to.into(), - min_extension.into(), - max_extension.into(), - ) - .unwrap_infallible(); - } -} - -/// A deployer that deploys a contract that has its ID derived from the provided -/// address and salt. -pub struct DeployerWithAddress { - env: Env, - address: Address, - salt: BytesN<32>, -} - -impl DeployerWithAddress { - /// Return the address of the contract defined by the deployer. - /// - /// This function can be called at anytime, before or after the contract is - /// deployed, because contract addresses are deterministic. - pub fn deployed_address(&self) -> Address { - self.env - .get_contract_id(self.address.to_object(), self.salt.to_object()) - .unwrap_infallible() - .into_val(&self.env) - } - - /// Deploy a contract that uses Wasm executable with provided hash. - /// - /// The address of the deployed contract is defined by the deployer address - /// and provided salt. - /// - /// Returns the deployed contract's address. - #[deprecated(note = "use deploy_v2")] - pub fn deploy(&self, wasm_hash: impl IntoVal>) -> Address { - let env = &self.env; - let address_obj = env - .create_contract( - self.address.to_object(), - wasm_hash.into_val(env).to_object(), - self.salt.to_object(), - ) - .unwrap_infallible(); - unsafe { Address::unchecked_new(env.clone(), address_obj) } - } - - /// Deploy a contract that uses Wasm executable with provided hash. - /// - /// The constructor args will be passed to the contract's constructor. Pass - /// `()` for contract's with no constructor or a constructor with zero - /// arguments. - /// - /// The address of the deployed contract is defined by the deployer address - /// and provided salt. - /// - /// Returns the deployed contract's address. - pub fn deploy_v2( - &self, - wasm_hash: impl IntoVal>, - constructor_args: A, - ) -> Address - where - A: ConstructorArgs, - { - let env = &self.env; - let address_obj = env - .create_contract_with_constructor( - self.address.to_object(), - wasm_hash.into_val(env).to_object(), - self.salt.to_object(), - constructor_args.into_val(env).to_object(), - ) - .unwrap_infallible(); - unsafe { Address::unchecked_new(env.clone(), address_obj) } - } -} - -pub struct DeployerWithAsset { - env: Env, - serialized_asset: Bytes, -} - -impl DeployerWithAsset { - /// Return the address of the contract defined by the deployer. - /// - /// This function can be called at anytime, before or after the contract is - /// deployed, because contract addresses are deterministic. - pub fn deployed_address(&self) -> Address { - self.env - .get_asset_contract_id(self.serialized_asset.to_object()) - .unwrap_infallible() - .into_val(&self.env) - } - - pub fn deploy(&self) -> Address { - self.env - .create_asset_contract(self.serialized_asset.to_object()) - .unwrap_infallible() - .into_val(&self.env) - } -} - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -mod testutils { - use crate::deploy::Deployer; - use crate::Address; - - impl crate::testutils::Deployer for Deployer { - fn get_contract_instance_ttl(&self, contract: &Address) -> u32 { - self.env - .host() - .get_contract_instance_live_until_ledger(contract.to_object()) - .unwrap() - .checked_sub(self.env.ledger().sequence()) - .unwrap() - } - - fn get_contract_code_ttl(&self, contract: &Address) -> u32 { - self.env - .host() - .get_contract_code_live_until_ledger(contract.to_object()) - .unwrap() - .checked_sub(self.env.ledger().sequence()) - .unwrap() - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/env.rs b/temp_sdk/soroban-sdk-26.0.1/src/env.rs deleted file mode 100644 index 216a42e..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/env.rs +++ /dev/null @@ -1,2240 +0,0 @@ -use core::convert::Infallible; - -#[cfg(target_family = "wasm")] -pub mod internal { - use core::convert::Infallible; - - pub use soroban_env_guest::*; - pub type EnvImpl = Guest; - pub type MaybeEnvImpl = Guest; - - // In the Guest case, Env::Error is already Infallible so there is no work - // to do to "reject an error": if an error occurs in the environment, the - // host will trap our VM and we'll never get here at all. - pub(crate) fn reject_err(_env: &Guest, r: Result) -> Result { - r - } -} - -#[cfg(not(target_family = "wasm"))] -pub mod internal { - use core::convert::Infallible; - - pub use soroban_env_host::*; - pub type EnvImpl = Host; - pub type MaybeEnvImpl = Option; - - // When we have `feature="testutils"` (or are in cfg(test)) we enable feature - // `soroban-env-{common,host}/testutils` which in turn adds the helper method - // `Env::escalate_error_to_panic` to the Env trait. - // - // When this is available we want to use it, because it works in concert - // with a _different_ part of the host that's also `testutils`-gated: the - // mechanism for emulating the WASM VM error-handling semantics with native - // contracts. In particular when a WASM contract calls a host function that - // fails with some error E, the host traps the VM (not returning to it at - // all) and propagates E to the caller of the contract. This is simulated in - // the native case by returning a (nontrivial) error E to us here, which we - // then "reject" back to the host, which stores E in a temporary cell inside - // any `TestContract` frame in progress and then _panics_, unwinding back to - // a panic-catcher it installed when invoking the `TestContract` frame, and - // then extracting E from the frame and returning it to its caller. This - // simulates the "crash, but catching the error" behavior of the WASM case. - // This only works if we panic via `escalate_error_to_panic`. - // - // (The reason we don't just panic_any() here and let the panic-catcher do a - // type-based catch is that there might _be_ no panic-catcher around us, and - // we want to print out a nice error message in that case too, which - // panic_any() does not do us the favor of producing. This is all very - // subtle. See also soroban_env_host::Host::escalate_error_to_panic.) - #[cfg(any(test, feature = "testutils"))] - pub(crate) fn reject_err(env: &Host, r: Result) -> Result { - r.map_err(|e| env.escalate_error_to_panic(e)) - } - - // When we're _not_ in a cfg enabling `soroban-env-{common,host}/testutils`, - // there is no `Env::escalate_error_to_panic` to call, so we just panic - // here. But this is ok because in that case there is also no multi-contract - // calling machinery set up, nor probably any panic-catcher installed that - // we need to hide error values for the benefit of. Any panic in this case - // is probably going to unwind completely anyways. No special case needed. - #[cfg(not(any(test, feature = "testutils")))] - pub(crate) fn reject_err(_env: &Host, r: Result) -> Result { - r.map_err(|e| panic!("{:?}", e)) - } - - #[doc(hidden)] - impl Convert for super::Env - where - EnvImpl: Convert, - { - type Error = >::Error; - fn convert(&self, f: F) -> Result { - self.env_impl.convert(f) - } - } -} - -pub use internal::xdr; -pub use internal::ContractTtlExtension; -pub use internal::ConversionError; -pub use internal::EnvBase; -pub use internal::Error; -pub use internal::MapObject; -pub use internal::SymbolStr; -pub use internal::TryFromVal; -pub use internal::TryIntoVal; -pub use internal::Val; -pub use internal::VecObject; - -pub trait IntoVal { - fn into_val(&self, e: &E) -> T; -} - -pub trait FromVal { - fn from_val(e: &E, v: &T) -> Self; -} - -impl FromVal for U -where - U: TryFromVal, -{ - fn from_val(e: &E, v: &T) -> Self { - U::try_from_val(e, v).unwrap_optimized() - } -} - -impl IntoVal for U -where - T: FromVal, -{ - fn into_val(&self, e: &E) -> T { - T::from_val(e, self) - } -} - -use crate::auth::InvokerContractAuthEntry; -use crate::unwrap::UnwrapInfallible; -use crate::unwrap::UnwrapOptimized; -use crate::InvokeError; -use crate::{ - crypto::Crypto, deploy::Deployer, events::Events, ledger::Ledger, logs::Logs, prng::Prng, - storage::Storage, Address, Vec, -}; -use internal::{ - AddressObject, Bool, BytesObject, DurationObject, I128Object, I256Object, I256Val, I64Object, - MuxedAddressObject, StorageType, StringObject, Symbol, SymbolObject, TimepointObject, - U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Void, -}; - -#[doc(hidden)] -#[derive(Clone)] -pub struct MaybeEnv { - maybe_env_impl: internal::MaybeEnvImpl, - #[cfg(any(test, feature = "testutils"))] - test_state: Option, -} - -#[cfg(target_family = "wasm")] -impl TryFrom for Env { - type Error = Infallible; - - fn try_from(_value: MaybeEnv) -> Result { - Ok(Env { - env_impl: internal::EnvImpl {}, - }) - } -} - -impl Default for MaybeEnv { - fn default() -> Self { - Self::none() - } -} - -#[cfg(target_family = "wasm")] -impl MaybeEnv { - // separate function to be const - pub const fn none() -> Self { - Self { - maybe_env_impl: internal::EnvImpl {}, - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl MaybeEnv { - // separate function to be const - pub const fn none() -> Self { - Self { - maybe_env_impl: None, - #[cfg(any(test, feature = "testutils"))] - test_state: None, - } - } -} - -#[cfg(target_family = "wasm")] -impl From for MaybeEnv { - fn from(value: Env) -> Self { - MaybeEnv { - maybe_env_impl: value.env_impl, - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFrom for Env { - type Error = ConversionError; - - fn try_from(value: MaybeEnv) -> Result { - if let Some(env_impl) = value.maybe_env_impl { - Ok(Env { - env_impl, - #[cfg(any(test, feature = "testutils"))] - test_state: value.test_state.unwrap_or_default(), - }) - } else { - Err(ConversionError) - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for MaybeEnv { - fn from(value: Env) -> Self { - MaybeEnv { - maybe_env_impl: Some(value.env_impl.clone()), - #[cfg(any(test, feature = "testutils"))] - test_state: Some(value.test_state.clone()), - } - } -} - -/// The [Env] type provides access to the environment the contract is executing -/// within. -/// -/// The [Env] provides access to information about the currently executing -/// contract, who invoked it, contract data, functions for signing, hashing, -/// etc. -/// -/// Most types require access to an [Env] to be constructed or converted. -#[derive(Clone)] -pub struct Env { - env_impl: internal::EnvImpl, - #[cfg(any(test, feature = "testutils"))] - test_state: EnvTestState, -} - -impl Default for Env { - #[cfg(not(any(test, feature = "testutils")))] - fn default() -> Self { - Self { - env_impl: Default::default(), - } - } - - #[cfg(any(test, feature = "testutils"))] - fn default() -> Self { - Self::new_with_config(EnvTestConfig::default()) - } -} - -#[cfg(any(test, feature = "testutils"))] -#[derive(Default, Clone)] -struct LastEnv { - test_name: String, - number: usize, -} - -#[cfg(any(test, feature = "testutils"))] -thread_local! { - static LAST_ENV: RefCell> = RefCell::new(None); -} - -#[cfg(any(test, feature = "testutils"))] -#[derive(Clone, Default)] -struct EnvTestState { - test_name: Option, - number: usize, - config: EnvTestConfig, - generators: Rc>, - auth_snapshot: Rc>, - snapshot: Option>, -} - -/// Config for changing the default behavior of the Env when used in tests. -#[cfg(any(test, feature = "testutils"))] -#[derive(Clone)] -pub struct EnvTestConfig { - /// Capture a test snapshot when the Env is dropped, causing a test snapshot - /// JSON file to be written to disk when the Env is no longer referenced. - /// Defaults to true. - pub capture_snapshot_at_drop: bool, - // NOTE: Next time a field needs to be added to EnvTestConfig it will be a breaking change, - // take the opportunity to make the current field private, new fields private, and settable via - // functions. Why: So that it is the last time a breaking change is needed to the type. -} - -#[cfg(any(test, feature = "testutils"))] -impl Default for EnvTestConfig { - fn default() -> Self { - Self { - capture_snapshot_at_drop: true, - } - } -} - -impl Env { - /// Panic with the given error. - /// - /// Equivalent to `panic!`, but with an error value instead of a string. - #[doc(hidden)] - #[cfg(feature = "experimental_spec_shaking_v2")] - #[inline(always)] - pub fn panic_with_error(&self, error: I) -> ! - where - I: Into + crate::SpecShakingMarker, - { - I::spec_shaking_marker(); - self.panic_with_error_inner(error.into()) - } - - /// Panic with the given error. - /// - /// Equivalent to `panic!`, but with an error value instead of a string. - #[doc(hidden)] - #[cfg(not(feature = "experimental_spec_shaking_v2"))] - #[inline(always)] - pub fn panic_with_error(&self, error: impl Into) -> ! { - self.panic_with_error_inner(error.into()) - } - - #[inline(always)] - fn panic_with_error_inner(&self, error: internal::Error) -> ! { - _ = internal::Env::fail_with_error(self, error); - #[cfg(target_family = "wasm")] - core::arch::wasm32::unreachable(); - #[cfg(not(target_family = "wasm"))] - unreachable!(); - } - - /// Get a [Storage] for accessing and updating persistent data owned by the - /// currently executing contract. - #[inline(always)] - pub fn storage(&self) -> Storage { - Storage::new(self) - } - - /// Get [Events] for publishing events associated with the - /// currently executing contract. - #[inline(always)] - pub fn events(&self) -> Events { - Events::new(self) - } - - /// Get a [Ledger] for accessing the current ledger. - #[inline(always)] - pub fn ledger(&self) -> Ledger { - Ledger::new(self) - } - - /// Get a deployer for deploying contracts. - #[inline(always)] - pub fn deployer(&self) -> Deployer { - Deployer::new(self) - } - - /// Get a [Crypto] for accessing the current cryptographic functions. - #[inline(always)] - pub fn crypto(&self) -> Crypto { - Crypto::new(self) - } - - /// # ⚠️ Hazardous Materials - /// - /// Get a [CryptoHazmat][crate::crypto::CryptoHazmat] for accessing the - /// cryptographic functions that are not generally recommended. Using them - /// incorrectly can introduce security vulnerabilities. Use [Crypto] if - /// possible. - #[cfg_attr(any(test, feature = "hazmat-crypto"), visibility::make(pub))] - #[cfg_attr(feature = "docs", doc(cfg(feature = "hazmat-crypto")))] - #[inline(always)] - pub(crate) fn crypto_hazmat(&self) -> crate::crypto::CryptoHazmat { - crate::crypto::CryptoHazmat::new(self) - } - - /// Get a [Prng] for accessing the current functions which provide pseudo-randomness. - /// - /// # Warning - /// - /// **The pseudo-random generator returned is not suitable for - /// security-sensitive work.** - #[inline(always)] - pub fn prng(&self) -> Prng { - Prng::new(self) - } - - /// Get the Address object corresponding to the current executing contract. - pub fn current_contract_address(&self) -> Address { - let address = internal::Env::get_current_contract_address(self).unwrap_infallible(); - unsafe { Address::unchecked_new(self.clone(), address) } - } - - #[doc(hidden)] - pub(crate) fn require_auth_for_args(&self, address: &Address, args: Vec) { - internal::Env::require_auth_for_args(self, address.to_object(), args.to_object()) - .unwrap_infallible(); - } - - #[doc(hidden)] - pub(crate) fn require_auth(&self, address: &Address) { - internal::Env::require_auth(self, address.to_object()).unwrap_infallible(); - } - - /// Invokes a function of a contract that is registered in the [Env]. - /// - /// # Panics - /// - /// Will panic if the `contract_id` does not match a registered contract, - /// `func` does not match a function of the referenced contract, or the - /// number of `args` do not match the argument count of the referenced - /// contract function. - /// - /// Will panic if the contract that is invoked fails or aborts in anyway. - /// - /// Will panic if the value returned from the contract cannot be converted - /// into the type `T`. - pub fn invoke_contract( - &self, - contract_address: &Address, - func: &crate::Symbol, - args: Vec, - ) -> T - where - T: TryFromVal, - { - let rv = internal::Env::call( - self, - contract_address.to_object(), - func.to_symbol_val(), - args.to_object(), - ) - .unwrap_infallible(); - T::try_from_val(self, &rv) - .map_err(|_| ConversionError) - .unwrap() - } - - /// Invokes a function of a contract that is registered in the [Env], - /// returns an error if the invocation fails for any reason. - pub fn try_invoke_contract( - &self, - contract_address: &Address, - func: &crate::Symbol, - args: Vec, - ) -> Result, Result> - where - T: TryFromVal, - E: TryFrom, - E::Error: Into, - { - let rv = internal::Env::try_call( - self, - contract_address.to_object(), - func.to_symbol_val(), - args.to_object(), - ) - .unwrap_infallible(); - match internal::Error::try_from_val(self, &rv) { - Ok(err) => Err(E::try_from(err).map_err(Into::into)), - Err(ConversionError) => Ok(T::try_from_val(self, &rv)), - } - } - - /// Authorizes sub-contract calls on behalf of the current contract. - /// - /// All the direct calls that the current contract performs are always - /// considered to have been authorized. This is only needed to authorize - /// deeper calls that originate from the next contract call from the current - /// contract. - /// - /// For example, if the contract A calls contract B, contract - /// B calls contract C and contract C calls `A.require_auth()`, then an - /// entry corresponding to C call has to be passed in `auth_entries`. It - /// doesn't matter if contract B called `require_auth` or not. If contract A - /// calls contract B again, then `authorize_as_current_contract` has to be - /// called again with the respective entries. - /// - /// When testing a contract call that uses `authorize_as_current_contract`, avoid - /// using [`mock_all_auths_allowing_non_root_auth`][Self::mock_all_auths_allowing_non_root_auth]. - /// A test that uses this mock will not fail if a missing or incorrect - /// `authorize_as_current_contract` call is present. It is recommended to use other - /// authorization mocking functions like [`mock_auths`][Self::mock_auths] - /// or [`set_auths`][Self::set_auths] if needed. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{ - /// auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, - /// contract, contractimpl, vec, Address, Env, IntoVal, Symbol, - /// }; - /// - /// // Contract C performs authorization for addr - /// #[contract] - /// pub struct ContractC; - /// - /// #[contractimpl] - /// impl ContractC { - /// pub fn do_auth(_env: Env, addr: Address, amount: i128) -> i128 { - /// addr.require_auth(); - /// amount - /// } - /// } - /// - /// // Contract B performs authorization for `addr` and invokes Contract C with - /// // `addr` and `amount` as arguments. - /// #[contract] - /// pub struct ContractB; - /// - /// #[contractimpl] - /// impl ContractB { - /// pub fn call_c(env: Env, addr: Address, contract_c: Address, amount: i128) -> i128 { - /// addr.require_auth(); - /// ContractCClient::new(&env, &contract_c).do_auth(&addr, &amount) - /// } - /// } - /// - /// // Contract A authorizes Contract B to call Contract C on its behalf with `addr` and - /// // `amount` as arguments. - /// #[contract] - /// pub struct ContractA; - /// - /// #[contractimpl] - /// impl ContractA { - /// pub fn call_b(env: Env, contract_b: Address, contract_c: Address, amount: i128) -> i128 { - /// let curr_contract = env.current_contract_address(); - /// // Authorize the sub-call Contract B makes to Contract C - /// env.authorize_as_current_contract(vec![ - /// &env, - /// InvokerContractAuthEntry::Contract(SubContractInvocation { - /// context: ContractContext { - /// contract: contract_c.clone(), - /// fn_name: Symbol::new(&env, "do_auth"), - /// args: vec![&env, curr_contract.into_val(&env), amount.into_val(&env)], - /// }, - /// sub_invocations: vec![&env], - /// }), - /// ]); - /// ContractBClient::new(&env, &contract_b).call_c(&curr_contract, &contract_c, &amount) - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_a = env.register(ContractA, ()); - /// let contract_b = env.register(ContractB, ()); - /// let contract_c = env.register(ContractC, ()); - /// - /// // Auths are not mocked to ensure `authorize_as_current_contract` - /// // is working as intended. If Contract A includes additional auths, consider - /// // using `mock_auths` or `set_auths` for those authorizations. - /// - /// let client = ContractAClient::new(&env, &contract_a); - /// let result = client.call_b(&contract_b, &contract_c, &100); - /// assert_eq!(result, 100); - /// } - /// ``` - pub fn authorize_as_current_contract(&self, auth_entries: Vec) { - internal::Env::authorize_as_curr_contract(self, auth_entries.to_object()) - .unwrap_infallible(); - } - - /// Get the [Logs] for logging debug events. - #[inline(always)] - #[deprecated(note = "use [Env::logs]")] - #[doc(hidden)] - pub fn logger(&self) -> Logs { - self.logs() - } - - /// Get the [Logs] for logging debug events. - #[inline(always)] - pub fn logs(&self) -> Logs { - Logs::new(self) - } -} - -#[doc(hidden)] -#[cfg(not(target_family = "wasm"))] -impl Env { - pub(crate) fn is_same_env(&self, other: &Self) -> bool { - self.env_impl.is_same(&other.env_impl) - } -} - -#[cfg(any(test, feature = "testutils"))] -use crate::testutils::cost_estimate::CostEstimate; -#[cfg(any(test, feature = "testutils"))] -use crate::{ - auth, - testutils::{ - budget::Budget, cost_estimate::NetworkInvocationResourceLimits, default_ledger_info, - Address as _, AuthSnapshot, AuthorizedInvocation, ContractFunctionSet, EventsSnapshot, - Generators, Ledger as _, MockAuth, MockAuthContract, Register, Snapshot, - SnapshotSourceInput, StellarAssetContract, StellarAssetIssuer, - }, - Bytes, BytesN, ConstructorArgs, -}; -#[cfg(any(test, feature = "testutils"))] -use core::{cell::RefCell, cell::RefMut}; -#[cfg(any(test, feature = "testutils"))] -use internal::{InvocationEvent, InvocationResourceLimits}; -#[cfg(any(test, feature = "testutils"))] -use soroban_ledger_snapshot::LedgerSnapshot; -#[cfg(any(test, feature = "testutils"))] -use std::{path::Path, rc::Rc}; -#[cfg(any(test, feature = "testutils"))] -use xdr::{LedgerEntry, LedgerKey, LedgerKeyContractData, SorobanAuthorizationEntry}; - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl Env { - #[doc(hidden)] - pub fn in_contract(&self) -> bool { - self.env_impl.has_frame().unwrap() - } - - #[doc(hidden)] - pub fn host(&self) -> &internal::Host { - &self.env_impl - } - - #[doc(hidden)] - pub(crate) fn with_generator(&self, f: impl FnOnce(RefMut<'_, Generators>) -> T) -> T { - f((*self.test_state.generators).borrow_mut()) - } - - /// Create an Env with the test config. - pub fn new_with_config(config: EnvTestConfig) -> Env { - struct EmptySnapshotSource(); - - impl internal::storage::SnapshotSource for EmptySnapshotSource { - fn get( - &self, - _key: &Rc, - ) -> Result, Option)>, soroban_env_host::HostError> - { - Ok(None) - } - } - - let rf = Rc::new(EmptySnapshotSource()); - - Env::new_for_testutils(config, rf, None, None, None) - } - - /// Change the test config of an Env. - pub fn set_config(&mut self, config: EnvTestConfig) { - self.test_state.config = config; - } - - /// Used by multiple constructors to configure test environments consistently. - fn new_for_testutils( - config: EnvTestConfig, - recording_footprint: Rc, - generators: Option>>, - ledger_info: Option, - snapshot: Option>, - ) -> Env { - // Store in the Env the name of the test it is for, and a number so that within a test - // where one or more Env's have been created they can be uniquely identified relative to - // each other. - - let test_name = match std::thread::current().name() { - // When doc tests are running they're all run with the thread name main. There's no way - // to detect which doc test is being run. - Some(name) if name != "main" => Some(name.to_owned()), - _ => None, - }; - let number = if let Some(ref test_name) = test_name { - LAST_ENV.with_borrow_mut(|l| { - if let Some(last_env) = l.as_mut() { - if test_name != &last_env.test_name { - last_env.test_name = test_name.clone(); - last_env.number = 1; - 1 - } else { - let next_number = last_env.number + 1; - last_env.number = next_number; - next_number - } - } else { - *l = Some(LastEnv { - test_name: test_name.clone(), - number: 1, - }); - 1 - } - }) - } else { - 1 - }; - - let storage = internal::storage::Storage::with_recording_footprint(recording_footprint); - let budget = internal::budget::Budget::default(); - let env_impl = internal::EnvImpl::with_storage_and_budget(storage, budget.clone()); - env_impl - .set_source_account(xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519( - xdr::Uint256([0; 32]), - ))) - .unwrap(); - env_impl - .set_diagnostic_level(internal::DiagnosticLevel::Debug) - .unwrap(); - env_impl.set_base_prng_seed([0; 32]).unwrap(); - - let auth_snapshot = Rc::new(RefCell::new(AuthSnapshot::default())); - let auth_snapshot_in_hook = auth_snapshot.clone(); - env_impl - .set_invocation_hook(Some(Rc::new(move |host, event| { - match event { - InvocationEvent::Start => {} - InvocationEvent::Finish => { - let new_auths = host - .get_authenticated_authorizations() - // If an error occurs getting the authenticated authorizations - // it means that no auth has occurred. - .unwrap(); - (*auth_snapshot_in_hook).borrow_mut().0.push(new_auths); - } - } - }))) - .unwrap(); - env_impl.enable_invocation_metering(); - env_impl - .set_invocation_resource_limits(Some(InvocationResourceLimits::mainnet())) - .unwrap(); - - let env = Env { - env_impl, - test_state: EnvTestState { - test_name, - number, - config, - generators: generators.unwrap_or_default(), - snapshot, - auth_snapshot, - }, - }; - - let ledger_info = ledger_info.unwrap_or_else(default_ledger_info); - env.ledger().set(ledger_info); - - env - } - - /// Returns the resources metered during the last top level contract - /// invocation. - /// - /// In order to get non-`None` results, `enable_invocation_metering` has to - /// be called and at least one invocation has to happen after that. - /// - /// Take the return value with a grain of salt. The returned resources mostly - /// correspond only to the operations that have happened during the host - /// invocation, i.e. this won't try to simulate the work that happens in - /// production scenarios (e.g. certain XDR roundtrips). This also doesn't try - /// to model resources related to the transaction size. - /// - /// The returned value is as useful as the preceding setup, e.g. if a test - /// contract is used instead of a Wasm contract, all the costs related to - /// VM instantiation and execution, as well as Wasm reads/rent bumps will be - /// missed. - /// - /// While the resource metering may be useful for contract optimization, - /// keep in mind that resource and fee estimation may be imprecise. Use - /// simulation with RPC in order to get the exact resources for submitting - /// the transactions to the network. - pub fn cost_estimate(&self) -> CostEstimate { - CostEstimate::new(self.clone()) - } - - /// Register a contract with the [Env] for testing. - /// - /// Pass the contract type when the contract is defined in the current crate - /// and is being registered natively. Pass the contract wasm bytes when the - /// contract has been loaded as wasm. - /// - /// Pass the arguments for the contract's constructor, or `()` if none. For - /// contracts with a constructor, use the contract's generated `Args` type - /// to construct the arguments with the appropriate types for invoking - /// the constructor during registration. - /// - /// Returns the address of the registered contract that is the same as the - /// contract id passed in. - /// - /// If you need to specify the address the contract should be registered at, - /// use [`Env::register_at`]. - /// - /// ### Examples - /// Register a contract defined in the current crate, by specifying the type - /// name: - /// ``` - /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol}; - /// - /// #[contract] - /// pub struct Contract; - /// - /// #[contractimpl] - /// impl Contract { - /// pub fn __constructor(_env: Env, _input: u32) { - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(Contract, ContractArgs::__constructor(&123,)); - /// } - /// ``` - /// Register a contract wasm, by specifying the wasm bytes: - /// ``` - /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; - /// - /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(WASM, ()); - /// } - /// ``` - pub fn register<'a, C, A>(&self, contract: C, constructor_args: A) -> Address - where - C: Register, - A: ConstructorArgs, - { - contract.register(self, None, constructor_args) - } - - /// Register a contract with the [Env] for testing. - /// - /// Passing a contract ID for the first arguments registers the contract - /// with that contract ID. - /// - /// Registering a contract that is already registered replaces it. - /// Use re-registration with caution as it does not exist in the real - /// (on-chain) environment. Specifically, the new contract's constructor - /// will be called again during re-registration. That behavior only exists - /// for this test utility and is not reproducible on-chain, where contract - /// Wasm updates don't cause constructor to be called. - /// - /// Pass the contract type when the contract is defined in the current crate - /// and is being registered natively. Pass the contract wasm bytes when the - /// contract has been loaded as wasm. - /// - /// Returns the address of the registered contract that is the same as the - /// contract id passed in. - /// - /// ### Examples - /// Register a contract defined in the current crate, by specifying the type - /// name: - /// ``` - /// use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, BytesN, Env, Symbol}; - /// - /// #[contract] - /// pub struct Contract; - /// - /// #[contractimpl] - /// impl Contract { - /// pub fn __constructor(_env: Env, _input: u32) { - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = Address::generate(&env); - /// env.register_at(&contract_id, Contract, (123_u32,)); - /// } - /// ``` - /// Register a contract wasm, by specifying the wasm bytes: - /// ``` - /// use soroban_sdk::{testutils::Address as _, Address, BytesN, Env}; - /// - /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = Address::generate(&env); - /// env.register_at(&contract_id, WASM, ()); - /// } - /// ``` - pub fn register_at( - &self, - contract_id: &Address, - contract: C, - constructor_args: A, - ) -> Address - where - C: Register, - A: ConstructorArgs, - { - contract.register(self, contract_id, constructor_args) - } - - /// Register a contract with the [Env] for testing. - /// - /// Passing a contract ID for the first arguments registers the contract - /// with that contract ID. Providing `None` causes the Env to generate a new - /// contract ID that is assigned to the contract. - /// - /// If a contract has a constructor defined, then it will be called with - /// no arguments. If a constructor takes arguments, use `register`. - /// - /// Registering a contract that is already registered replaces it. - /// Use re-registration with caution as it does not exist in the real - /// (on-chain) environment. Specifically, the new contract's constructor - /// will be called again during re-registration. That behavior only exists - /// for this test utility and is not reproducible on-chain, where contract - /// Wasm updates don't cause constructor to be called. - /// - /// Returns the address of the registered contract. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, BytesN, Env, Symbol}; - /// - /// #[contract] - /// pub struct HelloContract; - /// - /// #[contractimpl] - /// impl HelloContract { - /// pub fn hello(env: Env, recipient: Symbol) -> Symbol { - /// todo!() - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register_contract(None, HelloContract); - /// } - /// ``` - #[deprecated(note = "use `register`")] - pub fn register_contract<'a, T: ContractFunctionSet + 'static>( - &self, - contract_id: impl Into>, - contract: T, - ) -> Address { - self.register_contract_with_constructor(contract_id, contract, ()) - } - - /// Register a contract with the [Env] for testing. - /// - /// This acts the in the same fashion as `register_contract`, but allows - /// passing arguments to the contract's constructor. - /// - /// Passing a contract ID for the first arguments registers the contract - /// with that contract ID. Providing `None` causes the Env to generate a new - /// contract ID that is assigned to the contract. - /// - /// Registering a contract that is already registered replaces it. - /// Use re-registration with caution as it does not exist in the real - /// (on-chain) environment. Specifically, the new contract's constructor - /// will be called again during re-registration. That behavior only exists - /// for this test utility and is not reproducible on-chain, where contract - /// Wasm updates don't cause constructor to be called. - /// - /// Returns the address of the registered contract. - pub(crate) fn register_contract_with_constructor< - 'a, - T: ContractFunctionSet + 'static, - A: ConstructorArgs, - >( - &self, - contract_id: impl Into>, - contract: T, - constructor_args: A, - ) -> Address { - struct InternalContractFunctionSet(pub(crate) T); - impl internal::ContractFunctionSet for InternalContractFunctionSet { - fn call( - &self, - func: &Symbol, - env_impl: &internal::EnvImpl, - args: &[Val], - ) -> Option { - let env = Env { - env_impl: env_impl.clone(), - test_state: Default::default(), - }; - self.0.call( - crate::Symbol::try_from_val(&env, func) - .unwrap_infallible() - .to_string() - .as_str(), - env, - args, - ) - } - } - - let contract_id = if let Some(contract_id) = contract_id.into() { - contract_id.clone() - } else { - Address::generate(self) - }; - self.env_impl - .register_test_contract_with_constructor( - contract_id.to_object(), - Rc::new(InternalContractFunctionSet(contract)), - constructor_args.into_val(self).to_object(), - ) - .unwrap(); - contract_id - } - - /// Register a contract in a Wasm file with the [Env] for testing. - /// - /// Passing a contract ID for the first arguments registers the contract - /// with that contract ID. Providing `None` causes the Env to generate a new - /// contract ID that is assigned to the contract. - /// - /// Registering a contract that is already registered replaces it. - /// Use re-registration with caution as it does not exist in the real - /// (on-chain) environment. Specifically, the new contract's constructor - /// will be called again during re-registration. That behavior only exists - /// for this test utility and is not reproducible on-chain, where contract - /// Wasm updates don't cause constructor to be called. - /// - /// Returns the address of the registered contract. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{BytesN, Env}; - /// - /// const WASM: &[u8] = include_bytes!("../doctest_fixtures/contract.wasm"); - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// env.register_contract_wasm(None, WASM); - /// } - /// ``` - #[deprecated(note = "use `register`")] - pub fn register_contract_wasm<'a>( - &self, - contract_id: impl Into>, - contract_wasm: impl IntoVal, - ) -> Address { - let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm); - self.register_contract_with_optional_contract_id_and_executable( - contract_id, - xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())), - crate::vec![&self], - ) - } - - /// Register a contract in a Wasm file with the [Env] for testing. - /// - /// This acts the in the same fashion as `register_contract`, but allows - /// passing arguments to the contract's constructor. - /// - /// Passing a contract ID for the first arguments registers the contract - /// with that contract ID. Providing `None` causes the Env to generate a new - /// contract ID that is assigned to the contract. - /// - /// Registering a contract that is already registered replaces it. - /// Use re-registration with caution as it does not exist in the real - /// (on-chain) environment. Specifically, the new contract's constructor - /// will be called again during re-registration. That behavior only exists - /// for this test utility and is not reproducible on-chain, where contract - /// Wasm updates don't cause constructor to be called. - /// - /// Returns the address of the registered contract. - pub(crate) fn register_contract_wasm_with_constructor<'a>( - &self, - contract_id: impl Into>, - contract_wasm: impl IntoVal, - constructor_args: impl ConstructorArgs, - ) -> Address { - let wasm_hash: BytesN<32> = self.deployer().upload_contract_wasm(contract_wasm); - self.register_contract_with_optional_contract_id_and_executable( - contract_id, - xdr::ContractExecutable::Wasm(xdr::Hash(wasm_hash.into())), - constructor_args.into_val(self), - ) - } - - /// Register the built-in Stellar Asset Contract with provided admin address. - /// - /// Returns a utility struct that contains the contract ID of the registered - /// token contract, as well as methods to read and update issuer flags. - /// - /// The contract will wrap a randomly-generated Stellar asset. This function - /// is useful for using in the tests when an arbitrary token contract - /// instance is needed. - pub fn register_stellar_asset_contract_v2(&self, admin: Address) -> StellarAssetContract { - let issuer_pk = self.with_generator(|mut g| g.address()); - let issuer_id = xdr::AccountId(xdr::PublicKey::PublicKeyTypeEd25519(xdr::Uint256( - issuer_pk.clone(), - ))); - - let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount { - account_id: issuer_id.clone(), - })); - - if self.host().get_ledger_entry(&k).unwrap().is_none() { - let v = Rc::new(xdr::LedgerEntry { - data: xdr::LedgerEntryData::Account(xdr::AccountEntry { - account_id: issuer_id.clone(), - balance: 0, - flags: 0, - home_domain: Default::default(), - inflation_dest: None, - num_sub_entries: 0, - seq_num: xdr::SequenceNumber(0), - thresholds: xdr::Thresholds([1; 4]), - signers: xdr::VecM::default(), - ext: xdr::AccountEntryExt::V0, - }), - last_modified_ledger_seq: 0, - ext: xdr::LedgerEntryExt::V0, - }); - self.host().add_ledger_entry(&k, &v, None).unwrap(); - } - - let asset = xdr::Asset::CreditAlphanum4(xdr::AlphaNum4 { - asset_code: xdr::AssetCode4([b'a', b'a', b'a', 0]), - issuer: issuer_id.clone(), - }); - let create = xdr::HostFunction::CreateContract(xdr::CreateContractArgs { - contract_id_preimage: xdr::ContractIdPreimage::Asset(asset.clone()), - executable: xdr::ContractExecutable::StellarAsset, - }); - - let token_id: Address = self - .env_impl - .invoke_function(create) - .unwrap() - .try_into_val(self) - .unwrap(); - - let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap(); - self.env_impl - .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager) - .unwrap(); - let admin_result = self.try_invoke_contract::<(), Error>( - &token_id, - &soroban_sdk_macros::internal_symbol_short!("set_admin"), - (admin,).try_into_val(self).unwrap(), - ); - self.env_impl.set_auth_manager(prev_auth_manager).unwrap(); - admin_result.unwrap().unwrap(); - - let issuer = StellarAssetIssuer::new(self.clone(), issuer_id); - StellarAssetContract::new(token_id, issuer, asset) - } - - /// Register the built-in Stellar Asset Contract with provided admin address. - /// - /// Returns the contract ID of the registered token contract. - /// - /// The contract will wrap a randomly-generated Stellar asset. This function - /// is useful for using in the tests when an arbitrary token contract - /// instance is needed. - #[deprecated(note = "use [Env::register_stellar_asset_contract_v2]")] - pub fn register_stellar_asset_contract(&self, admin: Address) -> Address { - self.register_stellar_asset_contract_v2(admin).address() - } - - fn register_contract_with_optional_contract_id_and_executable<'a>( - &self, - contract_id: impl Into>, - executable: xdr::ContractExecutable, - constructor_args: Vec, - ) -> Address { - if let Some(contract_id) = contract_id.into() { - self.register_contract_with_contract_id_and_executable( - contract_id, - executable, - constructor_args, - ); - contract_id.clone() - } else { - self.register_contract_with_source(executable, constructor_args) - } - } - - fn register_contract_with_source( - &self, - executable: xdr::ContractExecutable, - constructor_args: Vec, - ) -> Address { - let args_vec: std::vec::Vec = - constructor_args.iter().map(|v| v.into_val(self)).collect(); - let constructor_args = args_vec.try_into().unwrap(); - let prev_auth_manager = self.env_impl.snapshot_auth_manager().unwrap(); - self.env_impl - .switch_to_recording_auth_inherited_from_snapshot(&prev_auth_manager) - .unwrap(); - let create_result = self - .env_impl - .invoke_function(xdr::HostFunction::CreateContractV2( - xdr::CreateContractArgsV2 { - contract_id_preimage: xdr::ContractIdPreimage::Address( - xdr::ContractIdPreimageFromAddress { - address: xdr::ScAddress::Contract(xdr::ContractId(xdr::Hash( - self.with_generator(|mut g| g.address()), - ))), - salt: xdr::Uint256([0; 32]), - }, - ), - executable, - constructor_args, - }, - )); - - self.env_impl.set_auth_manager(prev_auth_manager).unwrap(); - - create_result.unwrap().try_into_val(self).unwrap() - } - - /// Set authorizations and signatures in the environment which will be - /// consumed by contracts when they invoke [`Address::require_auth`] or - /// [`Address::require_auth_for_args`] functions. - /// - /// Requires valid signatures for the authorization to be successful. - /// - /// This function can also be called on contract clients. - /// - /// To mock auth for testing, without requiring valid signatures, use - /// [`mock_all_auths`][Self::mock_all_auths] or - /// [`mock_auths`][Self::mock_auths]. If mocking of auths is enabled, - /// calling [`set_auths`][Self::set_auths] disables any mocking. - pub fn set_auths(&self, auths: &[SorobanAuthorizationEntry]) { - self.env_impl - .set_authorization_entries(auths.to_vec()) - .unwrap(); - } - - /// Mock authorizations in the environment which will cause matching invokes - /// of [`Address::require_auth`] and [`Address::require_auth_for_args`] to - /// pass. - /// - /// This function can also be called on contract clients. - /// - /// Authorizations not matching a mocked auth will fail. - /// - /// To mock all auths, use [`mock_all_auths`][Self::mock_all_auths]. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::{Address as _, MockAuth, MockAuthInvoke}, IntoVal}; - /// - /// #[contract] - /// pub struct HelloContract; - /// - /// #[contractimpl] - /// impl HelloContract { - /// pub fn hello(env: Env, from: Address) { - /// from.require_auth(); - /// // TODO - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(HelloContract, ()); - /// - /// let client = HelloContractClient::new(&env, &contract_id); - /// let addr = Address::generate(&env); - /// client.mock_auths(&[ - /// MockAuth { - /// address: &addr, - /// invoke: &MockAuthInvoke { - /// contract: &contract_id, - /// fn_name: "hello", - /// args: (&addr,).into_val(&env), - /// sub_invokes: &[], - /// }, - /// }, - /// ]).hello(&addr); - /// } - /// ``` - pub fn mock_auths(&self, auths: &[MockAuth]) { - for a in auths { - self.register_at(a.address, MockAuthContract, ()); - } - let auths = auths - .iter() - .cloned() - .map(Into::into) - .collect::>(); - self.env_impl.set_authorization_entries(auths).unwrap(); - } - - /// Mock all calls to the [`Address::require_auth`] and - /// [`Address::require_auth_for_args`] functions in invoked contracts, - /// having them succeed as if authorization was provided. - /// - /// When mocking is enabled, if the [`Address`] being authorized is the - /// address of a contract, that contract's `__check_auth` function will not - /// be called, and the contract does not need to exist or be registered in - /// the test. - /// - /// When mocking is enabled, if the [`Address`] being authorized is the - /// address of an account, the account does not need to exist. - /// - /// This function can also be called on contract clients. - /// - /// To disable mocking, see [`set_auths`][Self::set_auths]. - /// - /// To access a list of auths that have occurred, see [`auths`][Self::auths]. - /// - /// It is not currently possible to mock a subset of auths. - /// - /// A test that uses `mock_all_auths` without verifying the resulting - /// authorization tree via [`auths`][Self::auths] can pass even when a contract - /// is missing a `require_auth` check. Use [`auths`][Self::auths] after - /// the contract call to assert that the expected authorizations were required. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, Env, Address, IntoVal, symbol_short}; - /// use soroban_sdk::testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}; - /// - /// #[contract] - /// pub struct HelloContract; - /// - /// #[contractimpl] - /// impl HelloContract { - /// pub fn hello(env: Env, from: Address) { - /// from.require_auth(); - /// // TODO - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(HelloContract, ()); - /// - /// env.mock_all_auths(); - /// - /// let client = HelloContractClient::new(&env, &contract_id); - /// let addr = Address::generate(&env); - /// client.hello(&addr); - /// - /// // Verify that the expected authorization was required. - /// assert_eq!( - /// env.auths(), - /// [( - /// addr.clone(), - /// AuthorizedInvocation { - /// function: AuthorizedFunction::Contract(( - /// contract_id, - /// symbol_short!("hello"), - /// (&addr,).into_val(&env), - /// )), - /// sub_invocations: [].into(), - /// } - /// )] - /// ); - /// } - /// ``` - pub fn mock_all_auths(&self) { - self.env_impl.switch_to_recording_auth(true).unwrap(); - } - - /// A version of [`mock_all_auths`][Self::mock_all_auths] that allows authorizations that are not - /// present in the root invocation. - /// - /// Refer to [`mock_all_auths`][Self::mock_all_auths] documentation for general information and - /// prefer using [`mock_all_auths`][Self::mock_all_auths] unless non-root authorization is required. - /// - /// The only difference from [`mock_all_auths`][Self::mock_all_auths] is that this won't return an - /// error when `require_auth` hasn't been called in the root invocation for - /// any given address. This is useful to test contracts that bundle calls to - /// another contract without atomicity requirements (i.e. any contract call - /// can be frontrun). - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, Env, Address, testutils::Address as _}; - /// - /// #[contract] - /// pub struct ContractA; - /// - /// #[contractimpl] - /// impl ContractA { - /// pub fn do_auth(env: Env, addr: Address) { - /// addr.require_auth(); - /// } - /// } - /// #[contract] - /// pub struct ContractB; - /// - /// #[contractimpl] - /// impl ContractB { - /// pub fn call_a(env: Env, contract_a: Address, addr: Address) { - /// // Notice there is no `require_auth` call here. - /// ContractAClient::new(&env, &contract_a).do_auth(&addr); - /// } - /// } - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_a = env.register(ContractA, ()); - /// let contract_b = env.register(ContractB, ()); - /// // The regular `env.mock_all_auths()` would result in the call - /// // failure. - /// env.mock_all_auths_allowing_non_root_auth(); - /// - /// let client = ContractBClient::new(&env, &contract_b); - /// let addr = Address::generate(&env); - /// client.call_a(&contract_a, &addr); - /// } - /// ``` - pub fn mock_all_auths_allowing_non_root_auth(&self) { - self.env_impl.switch_to_recording_auth(false).unwrap(); - } - - /// Returns a list of authorization trees that were seen during the last - /// contract or authorized host function invocation. - /// - /// Use this in tests to verify that the expected authorizations with the - /// expected arguments are required. - /// - /// The return value is a vector of authorizations represented by tuples of - /// `(address, AuthorizedInvocation)`. `AuthorizedInvocation` describes the - /// tree of `require_auth_for_args(address, args)` from the contract - /// functions (or `require_auth` with all the arguments of the function - /// invocation). It also might contain the authorized host functions ( - /// currently CreateContract is the only such function) in case if - /// corresponding host functions have been called. - /// - /// Refer to documentation for `AuthorizedInvocation` for detailed - /// information on its contents. - /// - /// The order of the returned vector is defined by the order of - /// [`Address::require_auth`] calls. Repeated calls to - /// [`Address::require_auth`] with the same address and args in the same - /// tree of contract invocations will appear only once in the vector. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, symbol_short, Address, Symbol, Env, IntoVal}; - /// - /// #[contract] - /// pub struct Contract; - /// - /// #[contractimpl] - /// impl Contract { - /// pub fn transfer(env: Env, address: Address, amount: i128) { - /// address.require_auth(); - /// } - /// pub fn transfer2(env: Env, address: Address, amount: i128) { - /// address.require_auth_for_args((amount / 2,).into_val(&env)); - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(Contract, ()); - /// let client = ContractClient::new(&env, &contract_id); - /// env.mock_all_auths(); - /// let address = Address::generate(&env); - /// client.transfer(&address, &1000_i128); - /// assert_eq!( - /// env.auths(), - /// [( - /// address.clone(), - /// AuthorizedInvocation { - /// function: AuthorizedFunction::Contract(( - /// client.address.clone(), - /// symbol_short!("transfer"), - /// (&address, 1000_i128,).into_val(&env) - /// )), - /// sub_invocations: [].into() - /// } - /// )] - /// ); - /// - /// client.transfer2(&address, &1000_i128); - /// assert_eq!( - /// env.auths(), - /// [( - /// address.clone(), - /// AuthorizedInvocation { - /// function: AuthorizedFunction::Contract(( - /// client.address.clone(), - /// symbol_short!("transfer2"), - /// // `transfer2` requires auth for (amount / 2) == (1000 / 2) == 500. - /// (500_i128,).into_val(&env) - /// )), - /// sub_invocations: [].into() - /// } - /// )] - /// ); - /// } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - pub fn auths(&self) -> std::vec::Vec<(Address, AuthorizedInvocation)> { - (*self.test_state.auth_snapshot) - .borrow() - .0 - .last() - .cloned() - .unwrap_or_default() - .into_iter() - .map(|(sc_addr, invocation)| { - ( - xdr::ScVal::Address(sc_addr).try_into_val(self).unwrap(), - AuthorizedInvocation::from_xdr(self, &invocation), - ) - }) - .collect() - } - - /// Invokes the special `__check_auth` function of contracts that implement - /// the custom account interface. - /// - /// `__check_auth` can't be called outside of the host-managed `require_auth` - /// calls. This test utility allows testing custom account contracts without - /// the need to setup complex contract call trees and enabling the enforcing - /// auth on the host side. - /// - /// This function requires to provide the template argument for error. Use - /// `soroban_sdk::Error` if `__check_auth` doesn't return a special - /// contract error and use the error with `contracterror` attribute - /// otherwise. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contracterror, contractimpl, testutils::{Address as _, BytesN as _}, vec, auth::Context, BytesN, Env, Vec, Val}; - /// - /// #[contracterror] - /// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] - /// #[repr(u32)] - /// pub enum NoopAccountError { - /// SomeError = 1, - /// } - /// #[contract] - /// struct NoopAccountContract; - /// #[contractimpl] - /// impl NoopAccountContract { - /// - /// #[allow(non_snake_case)] - /// pub fn __check_auth( - /// _env: Env, - /// _signature_payload: BytesN<32>, - /// signature: Val, - /// _auth_context: Vec, - /// ) -> Result<(), NoopAccountError> { - /// if signature.is_void() { - /// Err(NoopAccountError::SomeError) - /// } else { - /// Ok(()) - /// } - /// } - /// } - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let e: Env = Default::default(); - /// let account_contract = NoopAccountContractClient::new(&e, &e.register(NoopAccountContract, ())); - /// // Non-successful call of `__check_auth` with a `contracterror` error. - /// assert_eq!( - /// e.try_invoke_contract_check_auth::( - /// &account_contract.address, - /// &BytesN::from_array(&e, &[0; 32]), - /// ().into(), - /// &vec![&e], - /// ), - /// // The inner `Result` is for conversion error and will be Ok - /// // as long as a valid error type used. - /// Err(Ok(NoopAccountError::SomeError)) - /// ); - /// // Successful call of `__check_auth` with a `soroban_sdk::InvokeError` - /// // error - this should be compatible with any error type. - /// assert_eq!( - /// e.try_invoke_contract_check_auth::( - /// &account_contract.address, - /// &BytesN::from_array(&e, &[0; 32]), - /// 0_i32.into(), - /// &vec![&e], - /// ), - /// Ok(()) - /// ); - /// } - /// ``` - pub fn try_invoke_contract_check_auth( - &self, - contract: &Address, - signature_payload: &BytesN<32>, - signature: Val, - auth_context: &Vec, - ) -> Result<(), Result> - where - E: TryFrom, - E::Error: Into, - { - let args = Vec::from_array( - self, - [signature_payload.to_val(), signature, auth_context.to_val()], - ); - let res = self - .host() - .call_account_contract_check_auth(contract.to_object(), args.to_object()); - match res { - Ok(rv) => Ok(rv.into_val(self)), - Err(e) => Err(e.error.try_into().map_err(Into::into)), - } - } - - fn register_contract_with_contract_id_and_executable( - &self, - contract_address: &Address, - executable: xdr::ContractExecutable, - constructor_args: Vec, - ) { - let contract_id = contract_address.contract_id(); - let data_key = xdr::ScVal::LedgerKeyContractInstance; - let key = Rc::new(LedgerKey::ContractData(LedgerKeyContractData { - contract: xdr::ScAddress::Contract(contract_id.clone()), - key: data_key.clone(), - durability: xdr::ContractDataDurability::Persistent, - })); - - let instance = xdr::ScContractInstance { - executable, - storage: Default::default(), - }; - - let entry = Rc::new(LedgerEntry { - ext: xdr::LedgerEntryExt::V0, - last_modified_ledger_seq: 0, - data: xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry { - contract: xdr::ScAddress::Contract(contract_id.clone()), - key: data_key, - val: xdr::ScVal::ContractInstance(instance), - durability: xdr::ContractDataDurability::Persistent, - ext: xdr::ExtensionPoint::V0, - }), - }); - let live_until_ledger = self.ledger().sequence() + 1; - self.host() - .add_ledger_entry(&key, &entry, Some(live_until_ledger)) - .unwrap(); - self.env_impl - .call_constructor_for_stored_contract_unsafe(&contract_id, constructor_args.to_object()) - .unwrap(); - } - - /// Run the function as if executed by the given contract ID. - /// - /// Used to write or read contract data, or take other actions in tests for - /// setting up tests or asserting on internal state. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, Env, Symbol}; - /// - /// #[contract] - /// pub struct HelloContract; - /// - /// #[contractimpl] - /// impl HelloContract { - /// pub fn set_storage(env: Env, key: Symbol, val: Symbol) { - /// env.storage().persistent().set(&key, &val); - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(HelloContract, ()); - /// let client = HelloContractClient::new(&env, &contract_id); - /// - /// let key = Symbol::new(&env, "foo"); - /// let val = Symbol::new(&env, "bar"); - /// - /// // Set storage using the contract - /// client.set_storage(&key, &val); - /// - /// // Successfully read the storage key - /// let result = env.as_contract(&contract_id, || { - /// env.storage() - /// .persistent() - /// .get::(&key) - /// .unwrap() - /// }); - /// assert_eq!(result, val); - /// } - /// ``` - pub fn as_contract(&self, id: &Address, f: impl FnOnce() -> T) -> T { - let id = id.contract_id(); - let func = Symbol::from_small_str(""); - let mut t: Option = None; - self.env_impl - .with_test_contract_frame(id, func, || { - t = Some(f()); - Ok(().into()) - }) - .unwrap(); - t.unwrap() - } - - /// Run the function as if executed by the given contract ID. Returns an - /// error if the function execution fails for any reason. - /// - /// Used to write or read contract data, or take other actions in tests for - /// setting up tests or asserting on internal state. - /// - /// ### Examples - /// ``` - /// use soroban_sdk::{contract, contractimpl, xdr::{ScErrorCode, ScErrorType}, Env, Error, Symbol}; - /// - /// #[contract] - /// pub struct HelloContract; - /// - /// #[contractimpl] - /// impl HelloContract { - /// pub fn set_storage(env: Env, key: Symbol, val: Symbol) { - /// env.storage().persistent().set(&key, &val); - /// } - /// } - /// - /// #[test] - /// fn test() { - /// # } - /// # fn main() { - /// let env = Env::default(); - /// let contract_id = env.register(HelloContract, ()); - /// let client = HelloContractClient::new(&env, &contract_id); - /// - /// let key = Symbol::new(&env, "foo"); - /// let val = Symbol::new(&env, "bar"); - /// - /// // Set storage using the contract - /// client.set_storage(&key, &val); - /// - /// // Successfully read the storage key - /// let result = env.try_as_contract::(&contract_id, || { - /// env.storage() - /// .persistent() - /// .get::(&key) - /// .unwrap() - /// }); - /// assert_eq!(result, Ok(val)); - /// - /// // Attempting to extend TTL of a non-existent key throws an error - /// let new_key = Symbol::new(&env, "baz"); - /// let result = env.try_as_contract(&contract_id, || { - /// env.storage().persistent().extend_ttl(&new_key, 1, 100); - /// }); - /// assert_eq!( - /// result, - /// Err(Ok(Error::from_type_and_code( - /// ScErrorType::Storage, - /// ScErrorCode::MissingValue - /// ))) - /// ); - /// } - /// ``` - pub fn try_as_contract( - &self, - id: &Address, - f: impl FnOnce() -> T, - ) -> Result> - where - E: TryFrom, - E::Error: Into, - { - let id = id.contract_id(); - let func = Symbol::from_small_str(""); - let mut t: Option = None; - let result = self.env_impl.try_with_test_contract_frame(id, func, || { - t = Some(f()); - Ok(().into()) - }); - - match result { - Ok(_) => Ok(t.unwrap()), - Err(e) => Err(E::try_from(e.error).map_err(Into::into)), - } - } - - /// Creates a new Env loaded with the [`Snapshot`]. - /// - /// The ledger info and state in the snapshot are loaded into the Env. - /// - /// Events, as an output source only, are not loaded into the Env. - pub fn from_snapshot(s: Snapshot) -> Env { - Env::new_for_testutils( - EnvTestConfig::default(), - Rc::new(s.ledger.clone()), - Some(Rc::new(RefCell::new(s.generators))), - Some(s.ledger.ledger_info()), - Some(Rc::new(s.ledger.clone())), - ) - } - - /// Creates a new Env loaded with the ledger snapshot loaded from the file. - /// - /// The ledger info and state in the snapshot are loaded into the Env. - /// - /// Events, as an output source only, are not loaded into the Env. - /// - /// ### Panics - /// - /// If there is any error reading the file. - pub fn from_snapshot_file(p: impl AsRef) -> Env { - Self::from_snapshot(Snapshot::read_file(p).unwrap()) - } - - /// Create a snapshot from the Env's current state. - pub fn to_snapshot(&self) -> Snapshot { - Snapshot { - generators: (*self.test_state.generators).borrow().clone(), - auth: (*self.test_state.auth_snapshot).borrow().clone(), - ledger: self.to_ledger_snapshot(), - events: self.to_events_snapshot(), - } - } - - /// Create a snapshot file from the Env's current state. - /// - /// ### Panics - /// - /// If there is any error writing the file. - pub fn to_snapshot_file(&self, p: impl AsRef) { - self.to_snapshot().write_file(p).unwrap(); - } - - /// Creates a new Env loaded with the snapshot source. - /// - /// The ledger info and state from the snapshot source are loaded into the Env. - pub fn from_ledger_snapshot(input: impl Into) -> Env { - let SnapshotSourceInput { - source, - ledger_info, - snapshot, - } = input.into(); - - Env::new_for_testutils( - EnvTestConfig::default(), // TODO: Allow setting the config. - source, - None, - ledger_info, - snapshot, - ) - } - - /// Creates a new Env loaded with the ledger snapshot loaded from the file. - /// - /// ### Panics - /// - /// If there is any error reading the file. - pub fn from_ledger_snapshot_file(p: impl AsRef) -> Env { - Self::from_ledger_snapshot(LedgerSnapshot::read_file(p).unwrap()) - } - - /// Create a snapshot from the Env's current state. - pub fn to_ledger_snapshot(&self) -> LedgerSnapshot { - let snapshot = self.test_state.snapshot.clone().unwrap_or_default(); - let mut snapshot = (*snapshot).clone(); - snapshot.set_ledger_info(self.ledger().get()); - snapshot.update_entries(&self.host().get_stored_entries().unwrap()); - snapshot - } - - /// Create a snapshot file from the Env's current state. - /// - /// ### Panics - /// - /// If there is any error writing the file. - pub fn to_ledger_snapshot_file(&self, p: impl AsRef) { - self.to_ledger_snapshot().write_file(p).unwrap(); - } - - /// Create an events snapshot from the Env's current state. - pub(crate) fn to_events_snapshot(&self) -> EventsSnapshot { - EventsSnapshot( - self.host() - .get_events() - .unwrap() - .0 - .into_iter() - .filter(|e| match e.event.type_ { - // Keep only system and contract events, because event - // snapshots are used in test snapshots, and intended to be - // stable over time because the goal is to record meaningful - // observable behaviors. Diagnostic events are observable, - // but events have no stability guarantees and are intended - // to be used by developers when debugging, tracing, and - // observing, not by systems that integrate. - xdr::ContractEventType::System | xdr::ContractEventType::Contract => true, - xdr::ContractEventType::Diagnostic => false, - }) - .map(Into::into) - .collect(), - ) - } - - /// Get the budget that tracks the resources consumed for the environment. - #[deprecated(note = "use cost_estimate().budget()")] - pub fn budget(&self) -> Budget { - Budget::new(self.env_impl.budget_cloned()) - } -} - -#[cfg(any(test, feature = "testutils"))] -impl Drop for Env { - fn drop(&mut self) { - // If the env impl (Host) is finishable, that means this Env is the last - // Env to hold a reference to the Host. The Env should only write a test - // snapshot at that point when no other references to the host exist, - // because it is only when there are no other references that the host - // is being dropped. - if self.env_impl.can_finish() && self.test_state.config.capture_snapshot_at_drop { - self.to_test_snapshot_file(); - } - } -} - -#[doc(hidden)] -#[cfg(any(test, feature = "testutils"))] -impl Env { - /// Create a snapshot file for the currently executing test. - /// - /// Writes the file to the `test_snapshots/{test-name}.N.json` path where - /// `N` is incremented for each unique `Env` in the test. - /// - /// Use to record the observable behavior of a test, and changes to that - /// behavior over time. Commit the test snapshot file to version control and - /// watch for changes in it on contract change, SDK upgrade, protocol - /// upgrade, and other important events. - /// - /// No file will be created if the environment has no meaningful data such - /// as stored entries or events. - /// - /// ### Panics - /// - /// If there is any error writing the file. - pub(crate) fn to_test_snapshot_file(&self) { - let snapshot = self.to_snapshot(); - - // Don't write a snapshot that has no data in it. - if snapshot.ledger.entries().into_iter().count() == 0 - && snapshot.events.0.is_empty() - && snapshot.auth.0.is_empty() - { - return; - } - - // Determine path to write test snapshots to. - let Some(test_name) = &self.test_state.test_name else { - // If there's no test name, we're not in a test context, so don't write snapshots. - return; - }; - let number = self.test_state.number; - // Break up the test name into directories, using :: as the separator. - // The :: module separator cannot be written into the filename because - // some operating systems (e.g. Windows) do not allow the : character in - // filenames. - let test_name_path = test_name - .split("::") - .map(|p| std::path::Path::new(p).to_path_buf()) - .reduce(|p0, p1| p0.join(p1)) - .expect("test name to not be empty"); - let dir = std::path::Path::new("test_snapshots"); - let p = dir - .join(&test_name_path) - .with_extension(format!("{number}.json")); - - // Write test snapshots to file. - eprintln!("Writing test snapshot file for test {test_name:?} to {p:?}."); - snapshot.write_file(p).unwrap(); - } -} - -#[doc(hidden)] -impl internal::EnvBase for Env { - type Error = Infallible; - - // This exists to allow code in conversion paths to upgrade an Error to an - // Env::Error with some control granted to the underlying Env (and panic - // paths kept out of the host). We delegate this to our env_impl and then, - // since our own Error type is Infallible, immediately throw it into either - // the env_impl's Error escalation path (if testing), or just plain panic. - #[cfg(not(target_family = "wasm"))] - fn error_from_error_val(&self, e: crate::Error) -> Self::Error { - let host_err = self.env_impl.error_from_error_val(e); - #[cfg(any(test, feature = "testutils"))] - self.env_impl.escalate_error_to_panic(host_err); - #[cfg(not(any(test, feature = "testutils")))] - panic!("{:?}", host_err); - } - - // When targeting wasm we don't even need to do that, just delegate to - // the Guest's impl, which calls core::arch::wasm32::unreachable. - #[cfg(target_family = "wasm")] - #[allow(unreachable_code)] - fn error_from_error_val(&self, e: crate::Error) -> Self::Error { - self.env_impl.error_from_error_val(e) - } - - fn check_protocol_version_lower_bound(&self, v: u32) -> Result<(), Self::Error> { - Ok(self - .env_impl - .check_protocol_version_lower_bound(v) - .unwrap_optimized()) - } - - fn check_protocol_version_upper_bound(&self, v: u32) -> Result<(), Self::Error> { - Ok(self - .env_impl - .check_protocol_version_upper_bound(v) - .unwrap_optimized()) - } - - // Note: the function `escalate_error_to_panic` only exists _on the `Env` - // trait_ when the feature `soroban-env-common/testutils` is enabled. This - // is because the host wants to never have this function even _compiled in_ - // when building for production, as it might be accidentally called (we have - // mistakenly done so with conversion and comparison traits in the past). - // - // As a result, we only implement it here (fairly meaninglessly) when we're - // in `cfg(test)` (which enables `soroban-env-host/testutils` thus - // `soroban-env-common/testutils`) or when we've had our own `testutils` - // feature enabled (which does the same). - // - // See the `internal::reject_err` functions above for more detail about what - // it actually does (when implemented for real, on the host). In this - // not-very-serious impl, since `Self::Error` is `Infallible`, this instance - // can never actually be called and so its body is just a trivial - // transformation from one empty type to another, for Type System Reasons. - #[cfg(any(test, feature = "testutils"))] - fn escalate_error_to_panic(&self, e: Self::Error) -> ! { - match e {} - } - - fn bytes_copy_from_slice( - &self, - b: BytesObject, - b_pos: U32Val, - slice: &[u8], - ) -> Result { - Ok(self - .env_impl - .bytes_copy_from_slice(b, b_pos, slice) - .unwrap_optimized()) - } - - fn bytes_copy_to_slice( - &self, - b: BytesObject, - b_pos: U32Val, - slice: &mut [u8], - ) -> Result<(), Self::Error> { - Ok(self - .env_impl - .bytes_copy_to_slice(b, b_pos, slice) - .unwrap_optimized()) - } - - fn bytes_new_from_slice(&self, slice: &[u8]) -> Result { - Ok(self.env_impl.bytes_new_from_slice(slice).unwrap_optimized()) - } - - fn log_from_slice(&self, msg: &str, args: &[Val]) -> Result { - Ok(self.env_impl.log_from_slice(msg, args).unwrap_optimized()) - } - - fn string_copy_to_slice( - &self, - b: StringObject, - b_pos: U32Val, - slice: &mut [u8], - ) -> Result<(), Self::Error> { - Ok(self - .env_impl - .string_copy_to_slice(b, b_pos, slice) - .unwrap_optimized()) - } - - fn symbol_copy_to_slice( - &self, - b: SymbolObject, - b_pos: U32Val, - mem: &mut [u8], - ) -> Result<(), Self::Error> { - Ok(self - .env_impl - .symbol_copy_to_slice(b, b_pos, mem) - .unwrap_optimized()) - } - - fn string_new_from_slice(&self, slice: &[u8]) -> Result { - Ok(self - .env_impl - .string_new_from_slice(slice) - .unwrap_optimized()) - } - - fn symbol_new_from_slice(&self, slice: &[u8]) -> Result { - Ok(self - .env_impl - .symbol_new_from_slice(slice) - .unwrap_optimized()) - } - - fn map_new_from_slices(&self, keys: &[&str], vals: &[Val]) -> Result { - Ok(self - .env_impl - .map_new_from_slices(keys, vals) - .unwrap_optimized()) - } - - fn map_unpack_to_slice( - &self, - map: MapObject, - keys: &[&str], - vals: &mut [Val], - ) -> Result { - Ok(self - .env_impl - .map_unpack_to_slice(map, keys, vals) - .unwrap_optimized()) - } - - fn vec_new_from_slice(&self, vals: &[Val]) -> Result { - Ok(self.env_impl.vec_new_from_slice(vals).unwrap_optimized()) - } - - fn vec_unpack_to_slice(&self, vec: VecObject, vals: &mut [Val]) -> Result { - Ok(self - .env_impl - .vec_unpack_to_slice(vec, vals) - .unwrap_optimized()) - } - - fn symbol_index_in_strs(&self, key: Symbol, strs: &[&str]) -> Result { - Ok(self - .env_impl - .symbol_index_in_strs(key, strs) - .unwrap_optimized()) - } -} - -/////////////////////////////////////////////////////////////////////////////// -/// X-macro use: impl Env for SDK's Env -/////////////////////////////////////////////////////////////////////////////// - -// This is a helper macro used only by impl_env_for_sdk below. It consumes a -// token-tree of the form: -// -// {fn $fn_id:ident $args:tt -> $ret:ty} -// -// and produces the the corresponding method definition to be used in the -// SDK's Env implementation of the Env (calling through to the corresponding -// guest or host implementation). -macro_rules! sdk_function_helper { - {$mod_id:ident, fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty} - => - { - fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error> { - internal::reject_err(&self.env_impl, self.env_impl.$fn_id($($arg),*)) - } - }; -} - -// This is a callback macro that pattern-matches the token-tree passed by the -// x-macro (call_macro_with_all_host_functions) and produces a suite of -// forwarding-method definitions, which it places in the body of the declaration -// of the implementation of Env for the SDK's Env. -macro_rules! impl_env_for_sdk { - { - $( - // This outer pattern matches a single 'mod' block of the token-tree - // passed from the x-macro to this macro. It is embedded in a `$()*` - // pattern-repetition matcher so that it will match all provided - // 'mod' blocks provided. - $(#[$mod_attr:meta])* - mod $mod_id:ident $mod_str:literal - { - $( - // This inner pattern matches a single function description - // inside a 'mod' block in the token-tree passed from the - // x-macro to this macro. It is embedded in a `$()*` - // pattern-repetition matcher so that it will match all such - // descriptions. - $(#[$fn_attr:meta])* - { $fn_str:literal, $($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident $args:tt -> $ret:ty } - )* - } - )* - } - - => // The part of the macro above this line is a matcher; below is its expansion. - - { - // This macro expands to a single item: the implementation of Env for - // the SDK's Env struct used by client contract code running in a WASM VM. - #[doc(hidden)] - impl internal::Env for Env - { - $( - $( - // This invokes the guest_function_helper! macro above - // passing only the relevant parts of the declaration - // matched by the inner pattern above. It is embedded in two - // nested `$()*` pattern-repetition expanders that - // correspond to the pattern-repetition matchers in the - // match section, but we ignore the structure of the 'mod' - // block repetition-level from the outer pattern in the - // expansion, flattening all functions from all 'mod' blocks - // into the implementation of Env for Guest. - sdk_function_helper!{$mod_id, fn $fn_id $args -> $ret} - )* - )* - } - }; -} - -// Here we invoke the x-macro passing generate_env_trait as its callback macro. -internal::call_macro_with_all_host_functions! { impl_env_for_sdk } diff --git a/temp_sdk/soroban-sdk-26.0.1/src/error.rs b/temp_sdk/soroban-sdk-26.0.1/src/error.rs deleted file mode 100644 index a7386e4..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/error.rs +++ /dev/null @@ -1,37 +0,0 @@ -use core::convert::Infallible; - -use crate::xdr; - -/// InvokeError captures errors returned from the invocation of another -/// contract. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum InvokeError { - /// Abort occurs if the invoke contract panicks with a [`panic!`], or a host - /// function of the environment has a failure, or a runtime error occurs. - Abort, - /// Contract error occurs if the invoked contract function exited returning - /// an error or called [`panic_with_error!`][crate::panic_with_error!] with - /// a [`contracterror`][crate::contracterror]. - /// - /// If the contract defines a [`contracterror`][crate::contracterror] type - /// as part of its interface, this variant of the error will be convertible - /// to that type, but if that conversion failed then this variant of the - /// error would be used to represent the error. - Contract(u32), -} - -impl From for InvokeError { - fn from(e: crate::Error) -> Self { - if e.is_type(xdr::ScErrorType::Contract) { - InvokeError::Contract(e.get_code()) - } else { - InvokeError::Abort - } - } -} - -impl From for InvokeError { - fn from(_: Infallible) -> Self { - unreachable!() - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/events.rs b/temp_sdk/soroban-sdk-26.0.1/src/events.rs deleted file mode 100644 index a818d88..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/events.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Events contains types for publishing contract events. -use core::fmt::Debug; - -#[cfg(doc)] -use crate::{contracttype, Bytes, Map}; -use crate::{env::internal, unwrap::UnwrapInfallible, Env, IntoVal, Val, Vec}; - -// TODO: consolidate with host::events::TOPIC_BYTES_LENGTH_LIMIT -const TOPIC_BYTES_LENGTH_LIMIT: u32 = 32; - -/// Events publishes events for the currently executing contract. -/// -/// ``` -/// use soroban_sdk::Env; -/// -/// # use soroban_sdk::{contract, contractimpl, vec, map, Val, BytesN}; -/// # -/// # #[contract] -/// # pub struct Contract; -/// # -/// # #[contractimpl] -/// # impl Contract { -/// # pub fn f(env: Env) { -/// let event = env.events(); -/// let data = map![&env, (1u32, 2u32)]; -/// // topics can be represented with tuple up to a certain length -/// let topics0 = (); -/// let topics1 = (0u32,); -/// let topics2 = (0u32, 1u32); -/// let topics3 = (0u32, 1u32, 2u32); -/// let topics4 = (0u32, 1u32, 2u32, 3u32); -/// // topics can also be represented with a `Vec` with no length limit -/// let topics5 = vec![&env, 4u32, 5u32, 6u32, 7u32, 8u32]; -/// event.publish(topics0, data.clone()); -/// event.publish(topics1, data.clone()); -/// event.publish(topics2, data.clone()); -/// event.publish(topics3, data.clone()); -/// event.publish(topics4, data.clone()); -/// event.publish(topics5, data.clone()); -/// # } -/// # } -/// -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// # let env = Env::default(); -/// # let contract_id = env.register(Contract, ()); -/// # ContractClient::new(&env, &contract_id).f(); -/// # } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -#[derive(Clone)] -pub struct Events(Env); - -impl Debug for Events { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Events") - } -} - -#[cfg(any(test, feature = "testutils"))] -use crate::{testutils, xdr, FromVal}; - -pub trait Event { - fn topics(&self, env: &Env) -> Vec; - fn data(&self, env: &Env) -> Val; - - fn publish(&self, env: &Env) { - env.events().publish_event(self); - } - - /// Convert this event and the given contract_id into a [`xdr::ContractEvent`] object. - /// Used to compare Events to emitted events in tests. - #[cfg(any(test, feature = "testutils"))] - fn to_xdr(&self, env: &Env, contract_id: &crate::Address) -> xdr::ContractEvent { - xdr::ContractEvent { - ext: xdr::ExtensionPoint::V0, - type_: xdr::ContractEventType::Contract, - contract_id: Some(contract_id.contract_id()), - body: xdr::ContractEventBody::V0(xdr::ContractEventV0 { - topics: self.topics(env).into(), - data: xdr::ScVal::from_val(env, &self.data(env)), - }), - } - } -} - -pub trait Topics: IntoVal> {} - -impl Topics for Vec {} - -impl Events { - #[inline(always)] - pub(crate) fn env(&self) -> &Env { - &self.0 - } - - #[inline(always)] - pub(crate) fn new(env: &Env) -> Events { - Events(env.clone()) - } - - /// Publish an event defined using the [`contractevent`][crate::contractevent] macro. - #[inline(always)] - pub fn publish_event(&self, e: &(impl Event + ?Sized)) { - let env = self.env(); - internal::Env::contract_event(env, e.topics(env).to_object(), e.data(env)) - .unwrap_infallible(); - } - - /// Publish an event. - /// - /// Consider using [`contractevent`][crate::contractevent] instead of this function. - /// - /// Event data is specified in `data`. Data may be any value or - /// type, including types defined by contracts using [contracttype]. - /// - /// Event topics must not contain: - /// - /// - [Vec] - /// - [Map] - /// - [Bytes]/[BytesN][crate::BytesN] longer than 32 bytes - /// - [contracttype] - #[deprecated(note = "use the #[contractevent] macro on a contract event type")] - #[inline(always)] - pub fn publish(&self, topics: T, data: D) - where - T: Topics, - D: IntoVal, - { - let env = self.env(); - internal::Env::contract_event(env, topics.into_val(env).to_object(), data.into_val(env)) - .unwrap_infallible(); - } -} - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl testutils::Events for Events { - fn all(&self) -> testutils::ContractEvents { - let env = self.env(); - let vec: std::vec::Vec = self - .env() - .host() - .get_events() - .unwrap() - .0 - .into_iter() - .filter_map(|e| { - if !e.failed_call - && e.event.type_ == xdr::ContractEventType::Contract - && e.event.contract_id.is_some() - { - Some(e.event) - } else { - None - } - }) - .collect(); - testutils::ContractEvents::new(&env, vec) - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs b/temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs deleted file mode 100644 index a875902..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/into_val_for_contract_fn.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! IntoValForContractFn is an internal trait that is used by code generated -//! for the export of contract functions. The generated code calls the trait to -//! convert return values from their respective SDK types into Val. -//! -//! The trait has a blanket implementation for all types that already implement -//! IntoVal. -//! -//! When the `experimental_spec_shaking_v2` feature is enabled, this trait also -//! calls `SpecShakingMarker::spec_shaking_marker()` to ensure that type specs -//! are included in the WASM when types are used at external boundaries -//! (function return values). - -use crate::{Env, IntoVal, Val}; - -#[doc(hidden)] -#[deprecated( - note = "IntoValForContractFn is an internal trait and is not safe to use or implement" -)] -pub trait IntoValForContractFn { - fn into_val_for_contract_fn(self, env: &Env) -> Val; -} - -#[cfg(feature = "experimental_spec_shaking_v2")] -#[doc(hidden)] -#[allow(deprecated)] -impl IntoValForContractFn for T -where - T: IntoVal + crate::SpecShakingMarker, -{ - fn into_val_for_contract_fn(self, env: &Env) -> Val { - T::spec_shaking_marker(); - self.into_val(env) - } -} - -#[cfg(not(feature = "experimental_spec_shaking_v2"))] -#[doc(hidden)] -#[allow(deprecated)] -impl IntoValForContractFn for T -where - T: IntoVal, -{ - fn into_val_for_contract_fn(self, env: &Env) -> Val { - self.into_val(env) - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/iter.rs b/temp_sdk/soroban-sdk-26.0.1/src/iter.rs deleted file mode 100644 index 8dd6d5e..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/iter.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Iterators for use with collections like [Map], [Vec]. -//! -//! Collections are not guaranteed to contain values of the expected type as -//! they are stored on the host as [Val]s, so two iterators are provided: -//! -//! - **`try_iter()`** returns an iterator that yields `Result` for each -//! element, allowing the caller to handle conversion errors. -//! - **`iter()`** returns an iterator that unwraps each result, -//! panicking if any element cannot be converted to the declared type. -#[cfg(doc)] -use crate::{Map, Val, Vec}; - -use core::fmt::Debug; -use core::iter::FusedIterator; -use core::marker::PhantomData; - -pub trait UnwrappedEnumerable { - fn unwrapped(self) -> UnwrappedIter; -} - -impl UnwrappedEnumerable for I -where - I: Iterator>, - E: Debug, -{ - fn unwrapped(self) -> UnwrappedIter { - UnwrappedIter { - iter: self, - item_type: PhantomData, - error_type: PhantomData, - } - } -} - -#[derive(Clone)] -pub struct UnwrappedIter { - iter: I, - item_type: PhantomData, - error_type: PhantomData, -} - -impl Iterator for UnwrappedIter -where - I: Iterator>, - E: Debug, -{ - type Item = T; - - #[inline(always)] - fn next(&mut self) -> Option { - self.iter.next().map(Result::unwrap) - } - - #[inline(always)] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl DoubleEndedIterator for UnwrappedIter -where - I: Iterator> + DoubleEndedIterator, - E: Debug, -{ - #[inline(always)] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(Result::unwrap) - } -} - -impl FusedIterator for UnwrappedIter -where - I: Iterator> + FusedIterator, - E: Debug, -{ -} - -impl ExactSizeIterator for UnwrappedIter -where - I: Iterator> + ExactSizeIterator, - E: Debug, -{ - #[inline(always)] - fn len(&self) -> usize { - self.iter.len() - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/ledger.rs b/temp_sdk/soroban-sdk-26.0.1/src/ledger.rs deleted file mode 100644 index 52d251e..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/ledger.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Ledger contains types for retrieving information about the current ledger. -use crate::{env::internal, unwrap::UnwrapInfallible, BytesN, Env, TryIntoVal}; - -/// Ledger retrieves information about the current ledger. -/// -/// For more details about the ledger and the ledger header that the values in the Ledger are derived from, see: -/// - -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::Env; -/// -/// # use soroban_sdk::{contract, contractimpl, BytesN}; -/// # -/// # #[contract] -/// # pub struct Contract; -/// # -/// # #[contractimpl] -/// # impl Contract { -/// # pub fn f(env: Env) { -/// let ledger = env.ledger(); -/// -/// let sequence = ledger.sequence(); -/// let timestamp = ledger.timestamp(); -/// let network_id = ledger.network_id(); -/// # } -/// # } -/// # -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// # let env = Env::default(); -/// # let contract_id = env.register(Contract, ()); -/// # ContractClient::new(&env, &contract_id).f(); -/// # } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -#[derive(Clone)] -pub struct Ledger(Env); - -impl Ledger { - #[inline(always)] - pub(crate) fn env(&self) -> &Env { - &self.0 - } - - #[inline(always)] - pub(crate) fn new(env: &Env) -> Ledger { - Ledger(env.clone()) - } - - /// Returns the version of the protocol that the ledger created with. - #[deprecated(note = "Protocol version won't be available in the future")] - pub fn protocol_version(&self) -> u32 { - internal::Env::get_ledger_version(self.env()) - .unwrap_infallible() - .into() - } - - /// Returns the sequence number of the ledger. - /// - /// The sequence number is a unique number for each ledger - /// that is sequential, incremented by one for each new ledger. - pub fn sequence(&self) -> u32 { - internal::Env::get_ledger_sequence(self.env()) - .unwrap_infallible() - .into() - } - - /// Returns the maximum ledger sequence number that data can live to. - #[doc(hidden)] - pub fn max_live_until_ledger(&self) -> u32 { - internal::Env::get_max_live_until_ledger(self.env()) - .unwrap_infallible() - .into() - } - - /// Returns a unix timestamp for when the ledger was closed. - /// - /// The timestamp is the number of seconds, excluding leap seconds, that - /// have elapsed since unix epoch. Unix epoch is January 1st, 1970, at - /// 00:00:00 UTC. - /// - /// For more details see: - /// - - pub fn timestamp(&self) -> u64 { - internal::Env::get_ledger_timestamp(self.env()) - .unwrap_infallible() - .try_into_val(self.env()) - .unwrap() - } - - /// Returns the network identifier. - /// - /// This is SHA-256 hash of the network passphrase, for example - /// for the Public Network this returns: - /// > SHA256(Public Global Stellar Network ; September 2015) - /// - /// Returns for the Test Network: - /// > SHA256(Test SDF Network ; September 2015) - pub fn network_id(&self) -> BytesN<32> { - let env = self.env(); - let bin_obj = internal::Env::get_ledger_network_id(env).unwrap_infallible(); - unsafe { BytesN::<32>::unchecked_new(env.clone(), bin_obj) } - } -} - -#[cfg(any(test, feature = "testutils"))] -use crate::testutils; - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl testutils::Ledger for Ledger { - fn set(&self, li: testutils::LedgerInfo) { - let env = self.env(); - env.host().set_ledger_info(li).unwrap(); - } - - fn set_protocol_version(&self, protocol_version: u32) { - self.with_mut(|ledger_info| { - ledger_info.protocol_version = protocol_version; - }); - } - - fn set_sequence_number(&self, sequence_number: u32) { - self.with_mut(|ledger_info| { - ledger_info.sequence_number = sequence_number; - }); - } - - fn set_timestamp(&self, timestamp: u64) { - self.with_mut(|ledger_info| { - ledger_info.timestamp = timestamp; - }); - } - - fn set_network_id(&self, network_id: [u8; 32]) { - self.with_mut(|ledger_info| { - ledger_info.network_id = network_id; - }); - } - - fn set_base_reserve(&self, base_reserve: u32) { - self.with_mut(|ledger_info| { - ledger_info.base_reserve = base_reserve; - }); - } - - fn set_min_temp_entry_ttl(&self, min_temp_entry_ttl: u32) { - self.with_mut(|ledger_info| { - ledger_info.min_temp_entry_ttl = min_temp_entry_ttl; - }); - } - - fn set_min_persistent_entry_ttl(&self, min_persistent_entry_ttl: u32) { - self.with_mut(|ledger_info| { - ledger_info.min_persistent_entry_ttl = min_persistent_entry_ttl; - }); - } - - fn set_max_entry_ttl(&self, max_entry_ttl: u32) { - self.with_mut(|ledger_info| { - // For the sake of consistency across SDK methods, - // we always make TTL values to not include the current ledger. - // The actual network setting in env expects this to include - // the current ledger, so we need to add 1 here. - ledger_info.max_entry_ttl = max_entry_ttl.saturating_add(1); - }); - } - - fn get(&self) -> testutils::LedgerInfo { - let env = self.env(); - env.host().with_ledger_info(|li| Ok(li.clone())).unwrap() - } - - fn with_mut(&self, f: F) - where - F: FnMut(&mut internal::LedgerInfo), - { - let env = self.env(); - env.host().with_mut_ledger_info(f).unwrap(); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/lib.rs b/temp_sdk/soroban-sdk-26.0.1/src/lib.rs deleted file mode 100644 index 4b4ee96..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/lib.rs +++ /dev/null @@ -1,1255 +0,0 @@ -//! Soroban SDK supports writing smart contracts for the Wasm-powered [Soroban] smart contract -//! runtime, deployed on [Stellar]. -//! -//! ### Docs -//! -//! See [developers.stellar.org] for documentation about building smart contracts for [Stellar]. -//! -//! [developers.stellar.org]: https://developers.stellar.org -//! [Stellar]: https://stellar.org -//! [Soroban]: https://stellar.org/soroban -//! -//! ### Support -//! -//! The two most recent soroban-sdk major releases are supported with critical security fixes. -//! Critical security issues may be backported to earlier versions if practical, but not guaranteed. -//! General bugs are only fixed on, and new features are only added to, the latest major release. -//! -//! ### Features -//! -//! See [_features] for a list of all Cargo features and what they do. -//! -//! ### Migrating Major Versions -//! -//! See [_migrating] for a summary of how to migrate from one major version to another. -//! -//! ### Examples -//! -//! ```rust -//! use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; -//! -//! #[contract] -//! pub struct Contract; -//! -//! #[contractimpl] -//! impl Contract { -//! pub fn hello(env: Env, to: Symbol) -> Vec { -//! vec![&env, symbol_short!("Hello"), to] -//! } -//! } -//! -//! #[test] -//! fn test() { -//! # } -//! # #[cfg(feature = "testutils")] -//! # fn main() { -//! let env = Env::default(); -//! let contract_id = env.register(Contract, ()); -//! let client = ContractClient::new(&env, &contract_id); -//! -//! let words = client.hello(&symbol_short!("Dev")); -//! -//! assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); -//! } -//! # #[cfg(not(feature = "testutils"))] -//! # fn main() { } -//! ``` -//! -//! More examples are available at: -//! - -//! - - -#![cfg_attr(target_family = "wasm", no_std)] -#![cfg_attr(feature = "docs", feature(doc_cfg))] -#![allow(dead_code)] - -pub mod _features; -pub mod _migrating; - -#[cfg(all(target_family = "wasm", feature = "testutils"))] -compile_error!("'testutils' feature is not supported on 'wasm' target"); - -// When used in a no_std contract, provide a panic handler as one is required. -#[cfg(target_family = "wasm")] -#[panic_handler] -fn handle_panic(_: &core::panic::PanicInfo) -> ! { - core::arch::wasm32::unreachable() -} - -#[cfg(feature = "alloc")] -#[cfg_attr(feature = "docs", doc(cfg(feature = "alloc")))] -pub mod alloc; - -/// This const block contains link sections that need to end up in the final -/// build of any contract using the SDK. -/// -/// In Rust's build system sections only get included into the final build if -/// the object file containing those sections are processed by the linker, but -/// as an optimization step if no code is called in an object file it is -/// discarded. This has the unfortunate effect of causing anything else in -/// those object files, such as link sections, to be discarded. Placing anything -/// that must be included in the build inside an exported static or function -/// ensures the object files won't be discarded. wasm-bindgen does a similar -/// thing to this with a function, and so this seems to be a reasonably -/// accepted way to work around this limitation in the build system. The SDK -/// uses a static exported with name `_` that becomes a global because a global -/// is more unnoticeable, and takes up less bytes. -/// -/// The const block has no affect on the above problem and exists only to group -/// the static and link sections under a shared cfg. -/// -/// See https://github.com/stellar/rs-soroban-sdk/issues/383 for more details. -#[cfg(target_family = "wasm")] -const _: () = { - /// This exported static is guaranteed to end up in the final binary of any - /// importer, as a global. It exists to ensure the link sections are - /// included in the final build artifact. See notes above. - #[export_name = "_"] - static __: () = (); - - #[link_section = "contractenvmetav0"] - static __ENV_META_XDR: [u8; env::internal::meta::XDR.len()] = env::internal::meta::XDR; - - // Rustc version. - contractmeta!(key = "rsver", val = env!("RUSTC_VERSION"),); - - // Rust Soroban SDK version. Don't emit when the cfg is set. The cfg is set when building test - // wasms in this repository, so that every commit in this repo does not cause the test wasms in - // this repo to have a new hash due to the revision being embedded. The wasm hash gets embedded - // into a few places, such as test snapshots, or get used in test themselves where if they are - // constantly changing creates repetitive diffs. - #[cfg(not(soroban_sdk_internal_no_rssdkver_meta))] - contractmeta!( - key = "rssdkver", - val = concat!(env!("CARGO_PKG_VERSION"), "#", env!("GIT_REVISION")), - ); - - // An indicator of the spec shaking version in use. Signals to the stellar-cli that the .wasm - // needs to have its spec shaken. See soroban_spec::shaking for constants and version detection. - // The contractmeta! macro requires string literals, so we assert the literals match the - // constants defined in soroban_spec::shaking. - #[cfg(feature = "experimental_spec_shaking_v2")] - contractmeta!(key = "rssdk_spec_shaking", val = "2"); -}; - -// Re-exports of dependencies used by macros. -#[doc(hidden)] -pub mod reexports_for_macros { - pub use bytes_lit; - #[cfg(any(test, feature = "testutils"))] - pub use ctor; -} - -/// `debug_assert_in_contract!` asserts that the contract is currently executing within a -/// contract. The macro expands to an assertion when testutils are enabled or in tests, -/// otherwise it expands to nothing. -macro_rules! debug_assert_in_contract { - ($env:expr $(,)?) => {{ - { - #[cfg(any(test, feature = "testutils"))] - assert!( - ($env).in_contract(), - "this function is not accessible outside of a contract, wrap \ - the call with `env.as_contract()` to access it from a \ - particular contract" - ); - } - }}; -} - -// For internal use, use `debug_assert_in_contract!` instead. -/// Assert in contract asserts that the contract is currently executing within a -/// contract. The macro maps to code when testutils are enabled or in tests, -/// otherwise maps to nothing. -#[deprecated(note = "this macro is deprecated and will be removed in a future release")] -#[macro_export] -macro_rules! assert_in_contract { - ($env:expr $(,)?) => {{ - { - #[cfg(any(test, feature = "testutils"))] - assert!( - ($env).in_contract(), - "this function is not accessible outside of a contract, wrap \ - the call with `env.as_contract()` to access it from a \ - particular contract" - ); - } - }}; -} - -/// Create a short [Symbol] constant with the given string. -/// -/// A short symbol's maximum length is 9 characters. For longer symbols, use -/// [Symbol::new] to create the symbol at runtime. -/// -/// Valid characters are `a-zA-Z0-9_`. -/// -/// The [Symbol] is generated at compile time and returned as a const. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{symbol_short, Symbol}; -/// -/// let symbol = symbol_short!("a_str"); -/// assert_eq!(symbol, symbol_short!("a_str")); -/// ``` -pub use soroban_sdk_macros::symbol_short; - -/// Generates conversions from the repr(u32) enum from/into an `Error`. -/// -/// There are some constraints on the types that are supported: -/// - Enum must derive `Copy`. -/// - Enum variants must have an explicit integer literal. -/// - Enum variants must have a value convertible to u32. -/// -/// Includes the type in the contract spec so that clients can generate bindings -/// for the type. By default, spec entries are only generated for `pub` types -/// (or when `export = true` is explicitly set). -/// -/// ### `experimental_spec_shaking_v2` -/// -/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] -/// feature is enabled, spec entries are generated for all types regardless of -/// visibility, and markers are embedded that allow post-build tools to strip -/// entries for types that are not used at a contract boundary. See -/// [`_features`] for details. -/// -/// ### Examples -/// -/// Defining an error and capturing errors using the `try_` variant. -/// -/// ``` -/// use soroban_sdk::{contract, contracterror, contractimpl, Env}; -/// -/// #[contracterror] -/// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -/// #[repr(u32)] -/// pub enum Error { -/// MyError = 1, -/// AnotherError = 2, -/// } -/// -/// #[contract] -/// pub struct Contract; -/// -/// #[contractimpl] -/// impl Contract { -/// pub fn causeerror(env: Env) -> Result<(), Error> { -/// Err(Error::MyError) -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// -/// // Register the contract defined in this crate. -/// let contract_id = env.register(Contract, ()); -/// -/// // Create a client for calling the contract. -/// let client = ContractClient::new(&env, &contract_id); -/// -/// // Invoke contract causeerror function, but use the try_ variant that -/// // will capture the error so we can inspect. -/// let result = client.try_causeerror(); -/// assert_eq!(result, Err(Ok(Error::MyError))); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -/// -/// Testing invocations that cause errors with `should_panic` instead of `try_`. -/// -/// ```should_panic -/// # use soroban_sdk::{contract, contracterror, contractimpl, Env}; -/// # -/// # #[contracterror] -/// # #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -/// # #[repr(u32)] -/// # pub enum Error { -/// # MyError = 1, -/// # AnotherError = 2, -/// # } -/// # -/// # #[contract] -/// # pub struct Contract; -/// # -/// # #[contractimpl] -/// # impl Contract { -/// # pub fn causeerror(env: Env) -> Result<(), Error> { -/// # Err(Error::MyError) -/// # } -/// # } -/// # -/// #[test] -/// #[should_panic(expected = "ContractError(1)")] -/// fn test() { -/// # panic!("ContractError(1)"); -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// -/// // Register the contract defined in this crate. -/// let contract_id = env.register(Contract, ()); -/// -/// // Create a client for calling the contract. -/// let client = ContractClient::new(&env, &contract_id); -/// -/// // Invoke contract causeerror function. -/// client.causeerror(); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contracterror; - -/// Import a contract from its WASM file, generating a client, types, and -/// constant holding the contract file. -/// -/// The path given is relative to the workspace root, and not the current -/// file. -/// -/// Generates in the current module: -/// - A `Contract` trait that matches the contracts interface. -/// - A `ContractClient` struct that has functions for each function in the -/// contract. -/// - Types for all contract types defined in the contract. -/// -/// ### `experimental_spec_shaking_v2` -/// -/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] -/// feature is enabled, imported types are generated with `export = true` so -/// they produce spec entries and markers in the importing contract. Post-build -/// tools strip entries for imported types that are not used at the importing -/// contract's boundary. Without this feature, imported types use -/// `export = false` and do not produce spec entries. See [`_features`] for -/// details. -/// -/// ### SHA-256 Verification -/// -/// An optional `sha256` parameter can be provided to verify the integrity of -/// the WASM file at compile time. When provided, the macro computes the -/// SHA-256 hash of the WASM file at compile time and produces a compile error -/// if it does not match the provided value. The `sha256` argument must -/// be a hex-encoded SHA-256 digest (64 hex chars, no 0x prefix). -/// -/// ```ignore -/// mod contract_a { -/// soroban_sdk::contractimport!( -/// file = "contract_a.wasm", -/// sha256 = "d5bc0a5b4...", -/// ); -/// } -/// ``` -/// -/// ### Examples -/// -/// ```ignore -/// use soroban_sdk::{contractimpl, BytesN, Env, Symbol}; -/// -/// mod contract_a { -/// soroban_sdk::contractimport!(file = "contract_a.wasm"); -/// } -/// -/// pub struct ContractB; -/// -/// #[contractimpl] -/// impl ContractB { -/// pub fn add_with(env: Env, contract_id: BytesN<32>, x: u32, y: u32) -> u32 { -/// let client = contract_a::ContractClient::new(&env, contract_id); -/// client.add(&x, &y) -/// } -/// } -/// -/// #[test] -/// fn test() { -/// let env = Env::default(); -/// -/// // Register contract A using the imported WASM. -/// let contract_a_id = env.register_contract_wasm(None, contract_a::WASM); -/// -/// // Register contract B defined in this crate. -/// let contract_b_id = env.register(ContractB, ()); -/// -/// // Create a client for calling contract B. -/// let client = ContractBClient::new(&env, &contract_b_id); -/// -/// // Invoke contract B via its client. -/// let sum = client.add_with(&contract_a_id, &5, &7); -/// assert_eq!(sum, 12); -/// } -/// ``` -pub use soroban_sdk_macros::contractimport; - -/// Marks a type as being the type that contract functions are attached for. -/// -/// Use `#[contractimpl]` on impl blocks of this type to make those functions -/// contract functions. -/// -/// Note that a crate only ever exports a single contract. While there can be -/// multiple types in a crate with `#[contract]`, when built as a wasm file and -/// deployed the combination of all contract functions and all contracts within -/// a crate will be seen as a single contract. -/// -/// ### Examples -/// -/// Define a contract with one function, `hello`, and call it from within a test -/// using the generated client. -/// -/// ``` -/// use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; -/// -/// #[contract] -/// pub struct HelloContract; -/// -/// #[contractimpl] -/// impl HelloContract { -/// pub fn hello(env: Env, to: Symbol) -> Vec { -/// vec![&env, symbol_short!("Hello"), to] -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// let contract_id = env.register(HelloContract, ()); -/// let client = HelloContractClient::new(&env, &contract_id); -/// -/// let words = client.hello(&symbol_short!("Dev")); -/// -/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contract; - -/// Exports the publicly accessible functions to the Soroban environment. -/// -/// Functions that are publicly accessible in the implementation are invocable -/// by other contracts, or directly by transactions, when deployed. -/// -/// ### Notes -/// -/// Each public function's export name is derived from the function name alone, -/// without any type prefix or namespace. This means: -/// -/// - **Function names must be unique across all `#[contractimpl]` blocks in a -/// crate.** If two impl blocks define a function with the same name, their -/// Wasm exports will collide, producing build or linker errors. -/// -/// - **Importing a crate that contains `#[contractimpl]` blocks will pull its -/// exported functions into the importing crate's Wasm binary.** This is a -/// limitation of Rust — any `#[export_name = "..."]` function in a dependency -/// is included in the final binary. This can cause unexpected exports or name -/// collisions that are hard to diagnose. For this reason it is usually -/// inadvisable to import dependencies that use `#[contractimpl]`. -/// -/// ### Examples -/// -/// Define a contract with one function, `hello`, and call it from within a test -/// using the generated client. -/// -/// ``` -/// use soroban_sdk::{contract, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; -/// -/// #[contract] -/// pub struct HelloContract; -/// -/// #[contractimpl] -/// impl HelloContract { -/// pub fn hello(env: Env, to: Symbol) -> Vec { -/// vec![&env, symbol_short!("Hello"), to] -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// let contract_id = env.register(HelloContract, ()); -/// let client = HelloContractClient::new(&env, &contract_id); -/// -/// let words = client.hello(&symbol_short!("Dev")); -/// -/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contractimpl; - -/// Defines a contract trait with default function implementations that can be -/// used by contracts. -/// -/// The `contracttrait` macro generates a trait that contracts can implement -/// using `contractimpl`. Functions defined with default implementations in -/// the trait will be automatically exported as contract functions when a -/// contract implements the trait using `#[contractimpl(contracttrait)]`. -/// -/// This is useful for defining standard interfaces where some functions have -/// default implementations that can be optionally overridden. -/// -/// Note: The `contracttrait` macro is not required on traits, but without it -/// default functions will not be exported by contracts that implement the -/// trait. -/// -/// ### Macro Arguments -/// -/// - `crate_path` - The path to the soroban-sdk crate. Defaults to `soroban_sdk`. -/// - `spec_name` - The name for the spec type. Defaults to `{TraitName}Spec`. -/// - `spec_export` - Whether to export the spec for default functions. Defaults to `false`. -/// - `args_name` - The name for the args type. Defaults to `{TraitName}Args`. -/// - `client_name` - The name for the client type. Defaults to `{TraitName}Client`. -/// -/// ### Examples -/// -/// Define a trait with a default function and implement it in a contract: -/// -/// ``` -/// use soroban_sdk::{contract, contractimpl, contracttrait, Address, Env}; -/// -/// #[contracttrait] -/// pub trait Token { -/// fn balance(env: &Env, id: Address) -> i128 { -/// // ... -/// # todo!() -/// } -/// -/// // Default function. -/// fn transfer(env: &Env, from: Address, to: Address, amount: i128) { -/// // ... -/// # todo!() -/// } -/// } -/// -/// #[contract] -/// pub struct TokenContract; -/// -/// #[contractimpl(contracttrait)] -/// impl Token for TokenContract { -/// fn balance(env: &Env, id: Address) -> i128 { -/// // Provide a custom impl of balance. -/// // ... -/// # todo!() -/// } -/// } -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contracttrait; - -/// Generates a macro for a trait that calls -/// contractimpl_trait_default_fns_not_overridden with information about the trait. -/// -/// This macro is used internally and is not intended to be used directly by contracts. -#[doc(hidden)] -pub use soroban_sdk_macros::contractimpl_trait_macro; - -/// Generates code the same as contractimpl does, but for the default functions of a trait that are -/// not overridden. -/// -/// This macro is used internally and is not intended to be used directly by contracts. -#[doc(hidden)] -pub use soroban_sdk_macros::contractimpl_trait_default_fns_not_overridden; - -/// Adds a serialized SCMetaEntry::SCMetaV0 to the WASM contracts custom section -/// under the section name 'contractmetav0'. Contract developers can use this to -/// append metadata to their contract. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{contract, contractimpl, contractmeta, vec, symbol_short, BytesN, Env, Symbol, Vec}; -/// -/// contractmeta!(key="desc", val="hello world contract"); -/// -/// #[contract] -/// pub struct HelloContract; -/// -/// #[contractimpl] -/// impl HelloContract { -/// pub fn hello(env: Env, to: Symbol) -> Vec { -/// vec![&env, symbol_short!("Hello"), to] -/// } -/// } -/// -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// let contract_id = env.register(HelloContract, ()); -/// let client = HelloContractClient::new(&env, &contract_id); -/// -/// let words = client.hello(&symbol_short!("Dev")); -/// -/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contractmeta; - -/// Generates conversions from the struct/enum from/into a `Val`. -/// -/// There are some constraints on the types that are supported: -/// - Enums with integer values must have an explicit integer literal for every -/// variant. -/// - Enums with unit variants are supported. -/// - Enums with tuple-like variants with a maximum of one tuple field are -/// supported. The tuple field must be of a type that is also convertible to and -/// from `Val`. -/// - Enums with struct-like variants are not supported. -/// - Structs are supported. All fields must be of a type that is also -/// convertible to and from `Val`. -/// - All variant names, field names, and type names must be 10-characters or -/// less in length. -/// -/// Includes the type in the contract spec so that clients can generate bindings -/// for the type. By default, spec entries are only generated for `pub` types -/// (or when `export = true` is explicitly set). -/// -/// ### `experimental_spec_shaking_v2` -/// -/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] -/// feature is enabled, spec entries are generated for all types regardless of -/// visibility, and markers are embedded that allow post-build tools to strip -/// entries for types that are not used at a contract boundary. See -/// [`_features`] for details. -/// -/// ### Examples -/// -/// Defining a contract type that is a struct and use it in a contract. -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, Env, Symbol}; -/// -/// #[contracttype] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct State { -/// pub count: u32, -/// pub last_incr: u32, -/// } -/// -/// #[contract] -/// pub struct Contract; -/// -/// #[contractimpl] -/// impl Contract { -/// /// Increment increments an internal counter, and returns the value. -/// pub fn increment(env: Env, incr: u32) -> u32 { -/// // Get the current count. -/// let mut state = Self::get_state(env.clone()); -/// -/// // Increment the count. -/// state.count += incr; -/// state.last_incr = incr; -/// -/// // Save the count. -/// env.storage().persistent().set(&symbol_short!("STATE"), &state); -/// -/// // Return the count to the caller. -/// state.count -/// } -/// -/// /// Return the current state. -/// pub fn get_state(env: Env) -> State { -/// env.storage().persistent() -/// .get(&symbol_short!("STATE")) -/// .unwrap_or_else(|| State::default()) // If no value set, assume 0. -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// let contract_id = env.register(Contract, ()); -/// let client = ContractClient::new(&env, &contract_id); -/// -/// assert_eq!(client.increment(&1), 1); -/// assert_eq!(client.increment(&10), 11); -/// assert_eq!( -/// client.get_state(), -/// State { -/// count: 11, -/// last_incr: 10, -/// }, -/// ); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -/// -/// Defining contract types that are three different types of enums and using -/// them in a contract. -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, Symbol, Env}; -/// -/// /// A tuple enum is stored as a two-element vector containing the name of -/// /// the enum variant as a Symbol, then the value in the tuple. -/// #[contracttype] -/// #[derive(Clone, Debug, Eq, PartialEq)] -/// pub enum Color { -/// Red(Intensity), -/// Blue(Shade), -/// } -/// -/// /// A unit enum is stored as a single-element vector containing the name of -/// /// the enum variant as a Symbol. -/// #[contracttype] -/// #[derive(Clone, Debug, Eq, PartialEq)] -/// pub enum Shade { -/// Light, -/// Dark, -/// } -/// -/// /// An integer enum is stored as its integer value. -/// #[contracttype] -/// #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -/// #[repr(u32)] -/// pub enum Intensity { -/// Low = 1, -/// High = 2, -/// } -/// -/// #[contract] -/// pub struct Contract; -/// -/// #[contractimpl] -/// impl Contract { -/// /// Set the color. -/// pub fn set(env: Env, c: Color) { -/// env.storage().persistent().set(&symbol_short!("COLOR"), &c); -/// } -/// -/// /// Get the color. -/// pub fn get(env: Env) -> Option { -/// env.storage().persistent() -/// .get(&symbol_short!("COLOR")) -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// let contract_id = env.register(Contract, ()); -/// let client = ContractClient::new(&env, &contract_id); -/// -/// assert_eq!(client.get(), None); -/// -/// client.set(&Color::Red(Intensity::High)); -/// assert_eq!(client.get(), Some(Color::Red(Intensity::High))); -/// -/// client.set(&Color::Blue(Shade::Light)); -/// assert_eq!(client.get(), Some(Color::Blue(Shade::Light))); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contracttype; - -/// Generates conversions from the struct into a published event. -/// -/// Fields of the struct become topics and data parameters in the published event. -/// -/// Includes the event in the contract spec so that clients can generate bindings -/// for the type and downstream systems can understand the meaning of the event. -/// -/// ### `experimental_spec_shaking_v2` -/// -/// When the [`experimental_spec_shaking_v2`][_features#experimental_spec_shaking_v2] -/// feature is enabled, markers are embedded that allow post-build tools to strip -/// spec entries for events that are never published at a contract boundary. See -/// [`_features`] for details. -/// -/// ### Examples -/// -/// #### Define an Event -/// -/// The event will have a single fixed topic matching the name of the struct in lower snake -/// case. The fixed topic will appear before any topics listed as fields. In the example -/// below, the topics for the event will be: -/// - `"my_event"` -/// - u32 value from the `my_topic` field -/// -/// The event's data will be a [`Map`], containing a key-value pair for each field with the key -/// being the name as a [`Symbol`]. In the example below, the data for the event will be: -/// - key: my_event_data => val: u32 -/// - key: more_event_data => val: u64 -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::contractevent; -/// -/// // Define the event using the `contractevent` attribute macro. -/// #[contractevent] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct MyEvent { -/// // Mark fields as topics, for the value to be included in the events topic list so -/// // that downstream systems know to index it. -/// #[topic] -/// pub my_topic: u32, -/// // Fields not marked as topics will appear in the events data section. -/// pub my_event_data: u32, -/// pub more_event_data: u64, -/// } -/// -/// # fn main() { } -/// ``` -/// -/// #### Define an Event with Custom Topics -/// -/// Define a contract event with a custom list of fixed topics. -/// -/// The fixed topics can be change to another value. In the example -/// below, the topics for the event will be: -/// - `"my_contract"` -/// - `"an_event"` -/// - u32 value from the `my_topic` field -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::contractevent; -/// -/// // Define the event using the `contractevent` attribute macro. -/// #[contractevent(topics = ["my_contract", "an_event"])] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct MyEvent { -/// // Mark fields as topics, for the value to be included in the events topic list so -/// // that downstream systems know to index it. -/// #[topic] -/// pub my_topic: u32, -/// // Fields not marked as topics will appear in the events data section. -/// pub my_event_data: u32, -/// pub more_event_data: u64, -/// } -/// -/// # fn main() { } -/// ``` -/// -/// #### Define an Event with Other Data Formats -/// -/// The data format of the event is a map by default, but can alternatively be defined as a `vec` -/// or `single-value`. -/// -/// ##### Vec -/// -/// In the example below, the data for the event will be a [`Vec`] containing: -/// - u32 -/// - u64 -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::contractevent; -/// -/// // Define the event using the `contractevent` attribute macro. -/// #[contractevent(data_format = "vec")] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct MyEvent { -/// // Mark fields as topics, for the value to be included in the events topic list so -/// // that downstream systems know to index it. -/// #[topic] -/// pub my_topic: u32, -/// // Fields not marked as topics will appear in the events data section. -/// pub my_event_data: u32, -/// pub more_event_data: u64, -/// } -/// -/// # fn main() { } -/// ``` -/// -/// ##### Single Value -/// -/// In the example below, the data for the event will be a u32. -/// -/// When the data format is a single value there must be no more than one data field. -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::contractevent; -/// -/// // Define the event using the `contractevent` attribute macro. -/// #[contractevent(data_format = "single-value")] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct MyEvent { -/// // Mark fields as topics, for the value to be included in the events topic list so -/// // that downstream systems know to index it. -/// #[topic] -/// pub my_topic: u32, -/// // Fields not marked as topics will appear in the events data section. -/// pub my_event_data: u32, -/// } -/// -/// # fn main() { } -/// ``` -/// -/// #### A Full Example -/// -/// Defining an event, publishing it in a contract, and testing it. -/// -/// ``` -/// #![no_std] -/// use soroban_sdk::{contract, contractevent, contractimpl, contracttype, symbol_short, Env, Symbol}; -/// -/// // Define the event using the `contractevent` attribute macro. -/// #[contractevent] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct Increment { -/// // Mark fields as topics, for the value to be included in the events topic list so -/// // that downstream systems know to index it. -/// #[topic] -/// pub change: u32, -/// // Fields not marked as topics will appear in the events data section. -/// pub count: u32, -/// } -/// -/// #[contracttype] -/// #[derive(Clone, Default, Debug, Eq, PartialEq)] -/// pub struct State { -/// pub count: u32, -/// pub last_incr: u32, -/// } -/// -/// #[contract] -/// pub struct Contract; -/// -/// #[contractimpl] -/// impl Contract { -/// /// Increment increments an internal counter, and returns the value. -/// /// Publishes an event about the change in the counter. -/// pub fn increment(env: Env, incr: u32) -> u32 { -/// // Get the current count. -/// let mut state = Self::get_state(env.clone()); -/// -/// // Increment the count. -/// state.count += incr; -/// state.last_incr = incr; -/// -/// // Save the count. -/// env.storage().persistent().set(&symbol_short!("STATE"), &state); -/// -/// // Publish an event about the change. -/// Increment { -/// change: incr, -/// count: state.count, -/// }.publish(&env); -/// -/// // Return the count to the caller. -/// state.count -/// } -/// -/// /// Return the current state. -/// pub fn get_state(env: Env) -> State { -/// env.storage().persistent() -/// .get(&symbol_short!("STATE")) -/// .unwrap_or_else(|| State::default()) // If no value set, assume 0. -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// let contract_id = env.register(Contract, ()); -/// let client = ContractClient::new(&env, &contract_id); -/// -/// assert_eq!(client.increment(&1), 1); -/// assert_eq!(client.increment(&10), 11); -/// assert_eq!( -/// client.get_state(), -/// State { -/// count: 11, -/// last_incr: 10, -/// }, -/// ); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -pub use soroban_sdk_macros::contractevent; - -/// Generates a type that helps build function args for a contract trait. -pub use soroban_sdk_macros::contractargs; - -/// Generates a client for a contract trait. -/// -/// Can be used to create clients for contracts that live outside the current -/// crate, using a trait that has been published as a standard or shared -/// interface. -/// -/// Primarily useful when needing to generate a client for someone elses -/// contract where they have only shared a trait interface. -/// -/// Note that [`contractimpl`] also automatically generates a client, and so it -/// is unnecessary to use [`contractclient`] for contracts that live in the -/// current crate. -/// -/// Note that [`contractimport`] also automatically generates a client when -/// importing someone elses contract where they have shared a .wasm file. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{contract, contractclient, contractimpl, vec, symbol_short, BytesN, Env, Symbol, Vec}; -/// -/// #[contractclient(name = "Client")] -/// pub trait HelloInteface { -/// fn hello(env: Env, to: Symbol) -> Vec; -/// } -/// -/// #[contract] -/// pub struct HelloContract; -/// -/// #[contractimpl] -/// impl HelloContract { -/// pub fn hello(env: Env, to: Symbol) -> Vec { -/// vec![&env, symbol_short!("Hello"), to] -/// } -/// } -/// -/// #[test] -/// fn test() { -/// # } -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// let env = Env::default(); -/// -/// // Register the hello contract. -/// let contract_id = env.register(HelloContract, ()); -/// -/// // Create a client for the hello contract, that was constructed using -/// // the trait. -/// let client = Client::new(&env, &contract_id); -/// -/// let words = client.hello(&symbol_short!("Dev")); -/// -/// assert_eq!(words, vec![&env, symbol_short!("Hello"), symbol_short!("Dev"),]); -/// } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -pub use soroban_sdk_macros::contractclient; - -/// Generates a contract spec for a trait or impl. -/// -/// Note that [`contractimpl`] also generates a contract spec and it is in most -/// cases not necessary to use this macro. -#[doc(hidden)] -pub use soroban_sdk_macros::contractspecfn; - -/// Import a contract from its WASM file, generating a constant holding the -/// contract file. -/// -/// Note that [`contractimport`] also automatically imports the contract file -/// into a constant, and so it is usually unnecessary to use [`contractfile`] -/// directly, unless you specifically want to only load the contract file -/// without generating a client for it. -/// -/// ### SHA-256 Verification -/// -/// Unlike [`contractimport`], `contractfile` **requires** a `sha256` -/// parameter. The macro computes the SHA-256 hash of the WASM file at compile -/// time and produces a compile error if it does not match the provided value. -/// The `sha256` argument must be a hex-encoded SHA-256 digest (64 hex chars, no 0x prefix). -/// -/// ```ignore -/// soroban_sdk::contractfile!( -/// file = "contract_a.wasm", -/// sha256 = "d5bc0a5b4...", -/// ); -/// ``` -pub use soroban_sdk_macros::contractfile; - -/// Panic with the given error. -/// -/// The first argument in the list must be a reference to an [Env]. -/// -/// The second argument is an error value. The error value will be given to any -/// calling contract. -/// -/// Equivalent to `panic!`, but with an error value instead of a string. The -/// error value will be given to any calling contract. -/// -/// See [`contracterror`] for how to define an error type. -#[macro_export] -macro_rules! panic_with_error { - ($env:expr, $error:expr) => {{ - $env.panic_with_error($error); - }}; -} - -#[doc(hidden)] -#[deprecated(note = "use panic_with_error!")] -#[macro_export] -macro_rules! panic_error { - ($env:expr, $error:expr) => {{ - $crate::panic_with_error!($env, $error); - }}; -} - -/// An internal panic! variant that avoids including the string -/// when building for wasm (since it's just pointless baggage). -#[cfg(target_family = "wasm")] -macro_rules! sdk_panic { - ($_msg:literal) => { - panic!() - }; - () => { - panic!() - }; -} -#[cfg(not(target_family = "wasm"))] -macro_rules! sdk_panic { - ($msg:literal) => { - panic!($msg) - }; - () => { - panic!() - }; -} - -/// Assert a condition and panic with the given error if it is false. -/// -/// The first argument in the list must be a reference to an [Env]. -/// -/// The second argument is an expression that if resolves to `false` will cause -/// a panic with the error in the third argument. -/// -/// The third argument is an error value. The error value will be given to any -/// calling contract. -/// -/// Equivalent to `assert!`, but with an error value instead of a string. The -/// error value will be given to any calling contract. -/// -/// See [`contracterror`] for how to define an error type. -#[macro_export] -macro_rules! assert_with_error { - ($env:expr, $cond:expr, $error:expr) => {{ - if !($cond) { - $crate::panic_with_error!($env, $error); - } - }}; -} - -#[doc(hidden)] -pub mod unwrap; - -mod env; - -mod address; -pub mod address_payload; -mod muxed_address; -mod symbol; - -pub use env::{ConversionError, Env}; - -/// Raw value of the Soroban smart contract platform that types can be converted -/// to and from for storing, or passing between contracts. -/// -pub use env::Val; - -/// Used to do conversions between values in the Soroban environment. -pub use env::FromVal; -/// Used to do conversions between values in the Soroban environment. -pub use env::IntoVal; -/// Used to do conversions between values in the Soroban environment. -pub use env::TryFromVal; -/// Used to do conversions between values in the Soroban environment. -pub use env::TryIntoVal; - -// Used by generated code only. -#[doc(hidden)] -pub use env::EnvBase; -#[doc(hidden)] -pub use env::Error; -#[doc(hidden)] -pub use env::MapObject; -#[doc(hidden)] -pub use env::SymbolStr; -#[doc(hidden)] -pub use env::VecObject; - -mod try_from_val_for_contract_fn; -#[doc(hidden)] -#[allow(deprecated)] -pub use try_from_val_for_contract_fn::TryFromValForContractFn; - -mod into_val_for_contract_fn; -#[doc(hidden)] -#[allow(deprecated)] -pub use into_val_for_contract_fn::IntoValForContractFn; - -#[cfg(feature = "experimental_spec_shaking_v2")] -mod spec_shaking; -#[cfg(feature = "experimental_spec_shaking_v2")] -#[doc(hidden)] -pub use spec_shaking::SpecShakingMarker; - -#[doc(hidden)] -#[deprecated(note = "use storage")] -pub mod data { - #[doc(hidden)] - #[deprecated(note = "use storage::Storage")] - pub use super::storage::Storage as Data; -} -pub mod auth; -#[macro_use] -mod bytes; -pub mod crypto; -pub mod deploy; -mod error; -pub use error::InvokeError; -pub mod events; -pub use events::{Event, Topics}; -pub mod iter; -pub mod ledger; -pub mod logs; -mod map; -pub mod prng; -pub mod storage; -pub mod token; -mod vec; -pub use address::{Address, Executable}; -pub use bytes::{Bytes, BytesN}; -pub use map::Map; -pub use muxed_address::MuxedAddress; -pub use symbol::Symbol; -pub use vec::Vec; -mod num; -pub use num::{Duration, Timepoint, I256, U256}; -mod string; -pub use string::String; -mod tuple; - -mod constructor_args; -pub use constructor_args::ConstructorArgs; - -pub mod xdr; - -pub mod testutils; - -mod arbitrary_extra; - -mod tests; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/logs.rs b/temp_sdk/soroban-sdk-26.0.1/src/logs.rs deleted file mode 100644 index 34a6542..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/logs.rs +++ /dev/null @@ -1,170 +0,0 @@ -//! Logging contains types for logging debug events. -//! -//! See [`log`][crate::log] for how to conveniently log debug events. -use core::fmt::Debug; - -use crate::{env::internal::EnvBase, Env, Val}; - -/// Log a debug event. -/// -/// Takes a [Env], a literal string, and an optional trailing sequence of -/// arguments that may be any value that are convertible to [`Val`]. The -/// string and arguments are appended as-is to the log, as the body of a -/// structured diagnostic event. Such events may be emitted from the host as -/// auxiliary diagnostic XDR, or converted to strings later for debugging. -/// -/// `log!` statements are only enabled in non optimized builds that have -/// `debug-assertions` enabled. To enable `debug-assertions` add the following -/// lines to `Cargo.toml`, then build with the profile specified, `--profile -/// release-with-logs`. See the cargo docs for how to use [custom profiles]. -/// -/// ```toml -/// [profile.release-with-logs] -/// inherits = "release" -/// debug-assertions = true -/// ``` -/// -/// [custom profiles]: -/// https://doc.rust-lang.org/cargo/reference/profiles.html#custom-profiles -/// -/// ### Examples -/// -/// Log a string: -/// -/// ``` -/// use soroban_sdk::{log, Env}; -/// -/// let env = Env::default(); -/// -/// log!(&env, "a log entry"); -/// ``` -/// -/// Log a string with values: -/// -/// ``` -/// use soroban_sdk::{log, symbol_short, Symbol, Env}; -/// -/// let env = Env::default(); -/// -/// let value = 5; -/// log!(&env, "a log entry", value, symbol_short!("another")); -/// ``` -/// -/// Assert on logs in tests: -/// -/// ``` -/// # #[cfg(feature = "testutils")] -/// # { -/// use soroban_sdk::{log, symbol_short, Symbol, Env}; -/// -/// let env = Env::default(); -/// -/// let value = 5; -/// log!(&env, "a log entry", value, symbol_short!("another")); -/// -/// use soroban_sdk::testutils::Logs; -/// let logentry = env.logs().all().last().unwrap().clone(); -/// assert!(logentry.contains("[\"a log entry\", 5, another]")); -/// # } -/// ``` -#[macro_export] -macro_rules! log { - ($env:expr, $fmt:literal $(,)?) => { - if cfg!(debug_assertions) { - $env.logs().add($fmt, &[]); - } - }; - ($env:expr, $fmt:literal, $($args:expr),* $(,)?) => { - if cfg!(debug_assertions) { - $env.logs().add($fmt, &[ - $( - <_ as $crate::IntoVal>::into_val(&$args, $env) - ),* - ]); - } - }; -} - -/// Logs logs debug events. -/// -/// See [`log`][crate::log] for how to conveniently log debug events. -#[derive(Clone)] -pub struct Logs(Env); - -impl Debug for Logs { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Logs") - } -} - -impl Logs { - #[inline(always)] - pub(crate) fn env(&self) -> &Env { - &self.0 - } - - #[inline(always)] - pub(crate) fn new(env: &Env) -> Logs { - Logs(env.clone()) - } - - #[deprecated(note = "use [Logs::add]")] - #[inline(always)] - pub fn log(&self, msg: &'static str, args: &[Val]) { - self.add(msg, args); - } - - /// Log a debug event. - /// - /// Takes a literal string and a sequence of trailing values to add - /// as a log entry in the diagnostic event stream. - /// - /// See [`log`][crate::log] for how to conveniently log debug events. - #[inline(always)] - pub fn add(&self, msg: &'static str, args: &[Val]) { - if cfg!(debug_assertions) { - let env = self.env(); - env.log_from_slice(msg, args).unwrap(); - - #[cfg(any(test, feature = "testutils"))] - { - use crate::testutils::Logs; - std::println!("{}", self.all().last().unwrap()); - } - } - } -} - -#[cfg(any(test, feature = "testutils"))] -use crate::testutils; - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl testutils::Logs for Logs { - fn all(&self) -> std::vec::Vec { - use crate::xdr::{ - ContractEventBody, ContractEventType, ScSymbol, ScVal, ScVec, StringM, VecM, - }; - let env = self.env(); - let log_sym = ScSymbol(StringM::try_from("log").unwrap()); - let log_topics = ScVec(VecM::try_from(vec![ScVal::Symbol(log_sym)]).unwrap()); - env.host() - .get_diagnostic_events() - .unwrap() - .0 - .into_iter() - .filter_map(|e| match (&e.event.type_, &e.event.body) { - (ContractEventType::Diagnostic, ContractEventBody::V0(ce)) - if &ce.topics == &log_topics.0 => - { - Some(format!("{}", &e)) - } - _ => None, - }) - .collect::>() - } - - fn print(&self) { - std::println!("{}", self.all().join("\n")) - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/map.rs b/temp_sdk/soroban-sdk-26.0.1/src/map.rs deleted file mode 100644 index 45f9e88..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/map.rs +++ /dev/null @@ -1,1169 +0,0 @@ -use core::{ - cmp::Ordering, convert::Infallible, fmt::Debug, iter::FusedIterator, marker::PhantomData, -}; - -use crate::{ - iter::{UnwrappedEnumerable, UnwrappedIter}, - unwrap::{UnwrapInfallible, UnwrapOptimized}, -}; - -use super::{ - env::internal::{Env as _, MapObject, U32Val}, - ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, Vec, -}; - -#[cfg(not(target_family = "wasm"))] -use super::xdr::ScVal; - -#[cfg(doc)] -use crate::storage::Storage; - -/// Create a [Map] with the given key-value pairs. -/// -/// The first argument in the list must be a reference to an [Env], then the -/// key-value pairs follow in a tuple `(key, value)`. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{Env, Map, map}; -/// -/// let env = Env::default(); -/// let map = map![&env, (1, 10), (2, 20)]; -/// assert_eq!(map.len(), 2); -/// ``` -#[macro_export] -macro_rules! map { - ($env:expr $(,)?) => { - $crate::Map::new($env) - }; - ($env:expr, $(($k:expr, $v:expr $(,)?)),+ $(,)?) => { - $crate::Map::from_array($env, [$(($k, $v)),+]) - }; -} - -/// Map is a ordered key-value dictionary. -/// -/// The map is ordered by its keys. Iterating a map is stable and always returns -/// the keys and values in order of the keys. -/// -/// The map is stored in the Host and available to the Guest through the -/// functions defined on Map. Values stored in the Map are transmitted to the -/// Host as [Val]s, and when retrieved from the Map are transmitted back and -/// converted from [Val] back into their type. -/// -/// The pairs of keys and values in a Map are not guaranteed to be of type -/// `K`/`V` and conversion will fail if they are not. Most functions on Map have -/// a try_ variation that returns a Result that will be Err if the conversion fails. -/// Functions that are not prefixed with try_ will panic if conversion fails." -/// -/// There are some cases where this lack of guarantee is important: -/// -/// - When storing a Map that has been provided externally as a contract -/// function argument, be aware there is no guarantee that all pairs in the Map -/// will be of type `K` and `V`. It may be necessary to validate all pairs, -/// either before storing, or when loading with `try_` variation functions. -/// -/// - When accessing and iterating over a Map that has been provided externally -/// as a contract function input, and the contract needs to be resilient to -/// failure, use the `try_` variation functions. -/// -/// Maps have at most one entry per key. Setting a value for a key in the map -/// that already has a value for that key replaces the value. -/// -/// Map values can be stored as [Storage], or in other types like [Vec], [Map], -/// etc. -/// -/// ### Examples -/// -/// Maps can be created and iterated. -/// -/// ``` -/// use soroban_sdk::{Env, Map, map}; -/// -/// let env = Env::default(); -/// let map = map![&env, (2, 20), (1, 10)]; -/// assert_eq!(map.len(), 2); -/// assert_eq!(map.iter().next(), Some((1, 10))); -/// ``` -/// -/// Maps are ordered and so maps created with elements in different order will -/// be equal. -/// -/// ``` -/// use soroban_sdk::{Env, Map, map}; -/// -/// let env = Env::default(); -/// assert_eq!( -/// map![&env, (1, 10), (2, 20)], -/// map![&env, (2, 20), (1, 10)], -/// ) -/// ``` -#[derive(Clone)] -pub struct Map { - env: Env, - obj: MapObject, - _k: PhantomData, - _v: PhantomData, -} - -impl Eq for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ -} - -impl PartialEq for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - #[cfg(not(target_family = "wasm"))] - if !self.env.is_same_env(&other.env) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = self - .env - .obj_cmp(self.obj.to_val(), other.obj.to_val()) - .unwrap_infallible(); - v.cmp(&0) - } -} - -impl Debug for Map -where - K: IntoVal + TryFromVal + Debug + Clone, - K::Error: Debug, - V: IntoVal + TryFromVal + Debug + Clone, - V::Error: Debug, -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Map(")?; - let mut iter = self.try_iter(); - if let Some(x) = iter.next() { - write!(f, "{:?}", x)?; - } - for x in iter { - write!(f, ", {:?}", x)?; - } - write!(f, ")")?; - Ok(()) - } -} - -impl TryFromVal for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Error = Infallible; - - #[inline(always)] - fn try_from_val(env: &Env, obj: &MapObject) -> Result { - Ok(Map { - env: env.clone(), - obj: *obj, - _k: PhantomData, - _v: PhantomData, - }) - } -} - -impl TryFromVal for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(MapObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl TryFromVal> for Val -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Error = Infallible; - - fn try_from_val(_env: &Env, v: &Map) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal> for Val -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Error = Infallible; - - fn try_from_val(_env: &Env, v: &&Map) -> Result { - Ok(v.to_val()) - } -} - -impl From> for Val -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - #[inline(always)] - fn from(m: Map) -> Self { - m.obj.into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Map> for ScVal { - fn from(v: &Map) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From> for ScVal { - fn from(v: Map) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal> for ScVal { - type Error = ConversionError; - fn try_from_val(_e: &Env, v: &Map) -> Result { - Ok(v.into()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok(MapObject::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl Map { - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: MapObject) -> Self { - Self { - env, - obj, - _k: PhantomData, - _v: PhantomData, - } - } - - #[inline(always)] - pub fn env(&self) -> &Env { - &self.env - } - - #[inline(always)] - pub fn as_val(&self) -> &Val { - self.obj.as_val() - } - - #[inline(always)] - pub fn to_val(&self) -> Val { - self.obj.to_val() - } - - #[inline(always)] - pub(crate) fn as_object(&self) -> &MapObject { - &self.obj - } - - #[inline(always)] - pub(crate) fn to_object(&self) -> MapObject { - self.obj - } -} - -impl Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - /// Create an empty Map. - #[inline(always)] - pub fn new(env: &Env) -> Map { - unsafe { Self::unchecked_new(env.clone(), env.map_new().unwrap_infallible()) } - } - - /// Create a Map from the key-value pairs in the array. - #[inline(always)] - pub fn from_array(env: &Env, items: [(K, V); N]) -> Map { - let mut map = Map::::new(env); - for (k, v) in items { - map.set(k, v); - } - map - } - - /// Returns true if a key-value pair exists in the map with the given key. - #[inline(always)] - pub fn contains_key(&self, k: K) -> bool { - self.env - .map_has(self.obj, k.into_val(&self.env)) - .unwrap_infallible() - .into() - } - - /// Returns the value corresponding to the key or None if the map does not - /// contain a value with the specified key. - /// - /// ### Panics - /// - /// If the value corresponding to the key cannot be converted to type V. - #[inline(always)] - pub fn get(&self, k: K) -> Option { - self.try_get(k).unwrap_optimized() - } - - /// Returns the value corresponding to the key or None if the map does not - /// contain a value with the specified key. - /// - /// ### Errors - /// - /// If the value corresponding to the key cannot be converted to type V. - #[inline(always)] - pub fn try_get(&self, k: K) -> Result, V::Error> { - let env = self.env(); - let k = k.into_val(env); - let has = env.map_has(self.obj, k).unwrap_infallible().into(); - if has { - let v = env.map_get(self.obj, k).unwrap_infallible(); - V::try_from_val(env, &v).map(|val| Some(val)) - } else { - Ok(None) - } - } - - /// Returns the value corresponding to the key. - /// - /// ### Panics - /// - /// If the map does not contain a value with the specified key. - /// - /// If the value corresponding to the key cannot be converted to type V. - #[inline(always)] - pub fn get_unchecked(&self, k: K) -> V { - self.try_get_unchecked(k).unwrap_optimized() - } - - /// Returns the value corresponding to the key. - /// - /// ### Errors - /// - /// If the value corresponding to the key cannot be converted to type V. - /// - /// ### Panics - /// - /// If the map does not contain a value with the specified key. - #[inline(always)] - pub fn try_get_unchecked(&self, k: K) -> Result { - let env = self.env(); - let v = env.map_get(self.obj, k.into_val(env)).unwrap_infallible(); - V::try_from_val(env, &v) - } - - /// Set the value for the specified key. - /// - /// If the map contains a value corresponding to the key, the value is - /// replaced with the given value. - #[inline(always)] - pub fn set(&mut self, k: K, v: V) { - let env = self.env(); - self.obj = env - .map_put(self.obj, k.into_val(env), v.into_val(env)) - .unwrap_infallible(); - } - - /// Remove the value corresponding to the key. - /// - /// Returns `None` if the map does not contain a value with the specified - /// key. - #[inline(always)] - pub fn remove(&mut self, k: K) -> Option<()> { - let env = self.env(); - let k = k.into_val(env); - let has = env.map_has(self.obj, k).unwrap_infallible().into(); - if has { - self.obj = env.map_del(self.obj, k).unwrap_infallible(); - Some(()) - } else { - None - } - } - - /// Remove the value corresponding to the key. - /// - /// ### Panics - /// - /// If the map does not contain a value with the specified key. - #[inline(always)] - pub fn remove_unchecked(&mut self, k: K) { - let env = self.env(); - self.obj = env.map_del(self.obj, k.into_val(env)).unwrap_infallible(); - } - - /// Returns a [Vec] of all keys in the map, ordered in the map's key-sorted order. - /// - /// This method does not validate that the keys in the map are of type `K`. Since [Map] - /// keys are not guaranteed to be of type `K`, it is not guaranteed that all values - /// in the returned [Vec] will be of type `K`. - #[inline(always)] - pub fn keys(&self) -> Vec { - let env = self.env(); - let vec = env.map_keys(self.obj).unwrap_infallible(); - Vec::::try_from_val(env, &vec).unwrap() - } - - /// Returns a [Vec] of all values in the map, ordered in the map's key-sorted order. - /// - /// This method does not validate that the values in the map are of type `V`. Since [Map] - /// values are not guaranteed to be of type `V`, it is not guaranteed that all values - /// in the returned [Vec] will be of type `V`. - #[inline(always)] - pub fn values(&self) -> Vec { - let env = self.env(); - let vec = env.map_values(self.obj).unwrap_infallible(); - Vec::::try_from_val(env, &vec).unwrap() - } -} - -impl Map { - /// Returns true if the map is empty and contains no key-values. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the number of key-value pairs in the map. - #[inline(always)] - pub fn len(&self) -> u32 { - self.env().map_len(self.obj).unwrap_infallible().into() - } -} - -impl IntoIterator for Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Item = (K, V); - type IntoIter = UnwrappedIter, (K, V), ConversionError>; - - #[inline(always)] - fn into_iter(self) -> Self::IntoIter { - MapTryIter::new(self).unwrapped() - } -} - -impl Map -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - /// Returns an iterator over the key-value pairs of the map. - /// - /// Each entry is converted from [Val] to `(K, V)` as it is yielded. - /// - /// ### Panics - /// - /// If any key or value cannot be converted to its declared type. - /// Use [`try_iter`](Map::try_iter) to handle conversion errors. - #[inline(always)] - pub fn iter(&self) -> UnwrappedIter, (K, V), ConversionError> - where - K: Clone, - V: Clone, - { - self.clone().into_iter() - } - - /// Returns an iterator over the key-value pairs of the map, yielding - /// `Result<(K, V), ConversionError>` for each entry. - #[inline(always)] - pub fn try_iter(&self) -> MapTryIter - where - K: IntoVal + TryFromVal + Clone, - V: IntoVal + TryFromVal + Clone, - { - MapTryIter::new(self.clone()) - } - - #[inline(always)] - pub fn into_try_iter(self) -> MapTryIter - where - K: IntoVal + TryFromVal + Clone, - V: IntoVal + TryFromVal + Clone, - { - MapTryIter::new(self) - } -} - -#[derive(Clone)] -pub struct MapTryIter { - map: Map, - begin: u32, - end: u32, -} - -impl MapTryIter { - fn new(map: Map) -> Self { - Self { - begin: 0, - end: map.len(), - map, - } - } -} - -impl Iterator for MapTryIter -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - type Item = Result<(K, V), ConversionError>; - - fn next(&mut self) -> Option { - let env = self.map.env(); - if self.begin >= self.end { - return None; - } - let map_obj = self.map.to_object(); - let index_val: U32Val = self.begin.into(); - let key = env.map_key_by_pos(map_obj, index_val).unwrap_infallible(); - let value = env.map_val_by_pos(map_obj, index_val).unwrap_infallible(); - self.begin += 1; - - Some(Ok(( - match K::try_from_val(env, &key) { - Ok(k) => k, - Err(_) => return Some(Err(ConversionError)), - }, - match V::try_from_val(env, &value) { - Ok(v) => v, - Err(_) => return Some(Err(ConversionError)), - }, - ))) - } - - fn size_hint(&self) -> (usize, Option) { - let len = (self.end - self.begin) as usize; - (len, Some(len)) - } - - // TODO: Implement other functions as optimizations. -} - -impl DoubleEndedIterator for MapTryIter -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - fn next_back(&mut self) -> Option { - let env = self.map.env(); - if self.begin >= self.end { - return None; - } - self.end -= 1; - let map_obj = self.map.to_object(); - let index_val: U32Val = self.end.into(); - let key = env.map_key_by_pos(map_obj, index_val).unwrap_infallible(); - let value = env.map_val_by_pos(map_obj, index_val).unwrap_infallible(); - - Some(Ok(( - match K::try_from_val(env, &key) { - Ok(k) => k, - Err(_) => return Some(Err(ConversionError)), - }, - match V::try_from_val(env, &value) { - Ok(v) => v, - Err(_) => return Some(Err(ConversionError)), - }, - ))) - } - - // TODO: Implement other functions as optimizations. -} - -impl FusedIterator for MapTryIter -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ -} - -impl ExactSizeIterator for MapTryIter -where - K: IntoVal + TryFromVal, - V: IntoVal + TryFromVal, -{ - fn len(&self) -> usize { - (self.end - self.begin) as usize - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::vec; - - #[test] - fn test_map_macro() { - let env = Env::default(); - assert_eq!(map![&env], Map::::new(&env)); - assert_eq!(map![&env, (1, 10)], { - let mut v = Map::new(&env); - v.set(1, 10); - v - }); - assert_eq!(map![&env, (1, 10),], { - let mut v = Map::new(&env); - v.set(1, 10); - v - }); - assert_eq!(map![&env, (3, 30), (2, 20), (1, 10),], { - let mut v = Map::new(&env); - v.set(3, 30); - v.set(2, 20); - v.set(1, 10); - v - }); - assert_eq!(map![&env, (3, 30,), (2, 20,), (1, 10,),], { - let mut v = Map::new(&env); - v.set(3, 30); - v.set(2, 20); - v.set(1, 10); - v - }); - } - - #[test] - fn test_empty() { - let env = Env::default(); - - let map: Map<(), ()> = map![&env]; - assert_eq!(map.len(), 0); - } - - #[test] - fn test_map_to_val() { - let env = Env::default(); - - let map = Map::::from_array(&env, [(0, ()), (1, ()), (2, ()), (3, ())]); - let val: Val = map.clone().into_val(&env); - let rt: Map = val.into_val(&env); - - assert_eq!(map, rt); - } - - #[test] - fn test_ref_map_to_val() { - let env = Env::default(); - - let map = Map::::from_array(&env, [(0, ()), (1, ()), (2, ()), (3, ())]); - let val: Val = (&map).into_val(&env); - let rt: Map = val.into_val(&env); - - assert_eq!(map, rt); - } - - #[test] - fn test_double_ref_map_to_val() { - let env = Env::default(); - - let map = Map::::from_array(&env, [(0, ()), (1, ()), (2, ()), (3, ())]); - let val: Val = (&&map).into_val(&env); - let rt: Map = val.into_val(&env); - - assert_eq!(map, rt); - } - - #[test] - fn test_raw_vals() { - let env = Env::default(); - - let map: Map = map![&env, (1, true), (2, false)]; - assert_eq!(map.len(), 2); - assert_eq!(map.get(1), Some(true)); - assert_eq!(map.get(2), Some(false)); - assert_eq!(map.get(3), None); - } - - #[test] - fn test_iter() { - let env = Env::default(); - - let map: Map<(), ()> = map![&env]; - let mut iter = map.iter(); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - - let mut iter = map.iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some((0, 0))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next(), Some((1, 10))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next(), Some((2, 20))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some((3, 30))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some((4, 40))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut iter = map.iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some((0, 0))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next_back(), Some((4, 40))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next_back(), Some((3, 30))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some((1, 10))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some((2, 20))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - - let mut iter = map.iter().rev(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some((4, 40))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next_back(), Some((0, 0))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next_back(), Some((1, 10))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some((3, 30))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some((2, 20))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - } - - #[test] - #[should_panic(expected = "ConversionError")] - fn test_iter_panic_on_key_conversion() { - let env = Env::default(); - - let map: Map = map![&env, (1i64.into_val(&env), 2i32.into_val(&env)),]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - - let mut iter = map.iter(); - iter.next(); - } - - #[test] - #[should_panic(expected = "ConversionError")] - fn test_iter_panic_on_value_conversion() { - let env = Env::default(); - - let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env)),]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - - let mut iter = map.iter(); - iter.next(); - } - - #[test] - fn test_try_iter() { - let env = Env::default(); - - let map: Map<(), ()> = map![&env]; - let mut iter = map.iter(); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - - let mut iter = map.try_iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(Ok((0, 0)))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next(), Some(Ok((1, 10)))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next(), Some(Ok((2, 20)))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(Ok((3, 30)))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(Ok((4, 40)))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut iter = map.try_iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(Ok((0, 0)))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next_back(), Some(Ok((4, 40)))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next_back(), Some(Ok((3, 30)))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(Ok((1, 10)))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(Ok((2, 20)))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - - let mut iter = map.try_iter().rev(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(Ok((4, 40)))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next_back(), Some(Ok((0, 0)))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next_back(), Some(Ok((1, 10)))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(Ok((3, 30)))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(Ok((2, 20)))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - } - - #[test] - fn test_iter_error_on_key_conversion() { - let env = Env::default(); - - let map: Map = map![ - &env, - (1i32.into_val(&env), 2i32.into_val(&env)), - (3i64.into_val(&env), 4i32.into_val(&env)), - ]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - - let mut iter = map.try_iter(); - assert_eq!(iter.next(), Some(Ok((1, 2)))); - assert_eq!(iter.next(), Some(Err(ConversionError))); - } - - #[test] - fn test_iter_error_on_value_conversion() { - let env = Env::default(); - - let map: Map = map![ - &env, - (1i32.into_val(&env), 2i32.into_val(&env)), - (3i32.into_val(&env), 4i64.into_val(&env)), - ]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - - let mut iter = map.try_iter(); - assert_eq!(iter.next(), Some(Ok((1, 2)))); - assert_eq!(iter.next(), Some(Err(ConversionError))); - } - - #[test] - fn test_keys() { - let env = Env::default(); - - let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - let keys = map.keys(); - assert_eq!(keys, vec![&env, 0, 1, 2, 3, 4]); - } - - #[test] - fn test_values() { - let env = Env::default(); - - let map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - let values = map.values(); - assert_eq!(values, vec![&env, 0, 10, 20, 30, 40]); - } - - #[test] - fn test_from_array() { - let env = Env::default(); - - let map = Map::from_array(&env, [(0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]); - assert_eq!(map, map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]); - - let map: Map = Map::from_array(&env, []); - assert_eq!(map, map![&env]); - } - - #[test] - fn test_contains_key() { - let env = Env::default(); - - let map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - - // contains all assigned keys - for i in 0..map.len() { - assert_eq!(true, map.contains_key(i)); - } - - // does not contain keys outside range - assert_eq!(map.contains_key(6), false); - assert_eq!(map.contains_key(u32::MAX), false); - assert_eq!(map.contains_key(8), false); - } - - #[test] - fn test_is_empty() { - let env = Env::default(); - - let mut map: Map = Map::new(&env); - assert_eq!(map.is_empty(), true); - map.set(0, 0); - assert_eq!(map.is_empty(), false); - } - - #[test] - fn test_get() { - let env = Env::default(); - - let map: Map = map![&env, (0, 0), (1, 10)]; - assert_eq!(map.get(0), Some(0)); - assert_eq!(map.get(1), Some(10)); - assert_eq!(map.get(2), None); - } - - #[test] - fn test_get_none_on_key_type_mismatch() { - let env = Env::default(); - - let map: Map = map![ - &env, - (1i32.into_val(&env), 2i32.into_val(&env)), - (3i64.into_val(&env), 4i32.into_val(&env)), - ]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - assert_eq!(map.get(1), Some(2)); - assert_eq!(map.get(3), None); - } - - #[test] - #[should_panic(expected = "ConversionError")] - fn test_get_panics_on_value_conversion() { - let env = Env::default(); - - let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env)),]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - let _ = map.get(1); - } - - #[test] - fn test_try_get() { - let env = Env::default(); - - let map: Map = map![&env, (0, 0), (1, 10)]; - assert_eq!(map.try_get(0), Ok(Some(0))); - assert_eq!(map.try_get(1), Ok(Some(10))); - assert_eq!(map.try_get(2), Ok(None)); - } - - #[test] - fn test_try_get_none_on_key_type_mismatch() { - let env = Env::default(); - - let map: Map = map![ - &env, - (1i32.into_val(&env), 2i32.into_val(&env)), - (3i64.into_val(&env), 4i32.into_val(&env)), - ]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - assert_eq!(map.try_get(1), Ok(Some(2))); - assert_eq!(map.try_get(3), Ok(None)); - } - - #[test] - fn test_try_get_errors_on_value_conversion() { - let env = Env::default(); - - let map: Map = map![ - &env, - (1i32.into_val(&env), 2i32.into_val(&env)), - (3i32.into_val(&env), 4i64.into_val(&env)), - ]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - assert_eq!(map.try_get(1), Ok(Some(2))); - assert_eq!(map.try_get(3), Err(ConversionError)); - } - - #[test] - fn test_get_unchecked() { - let env = Env::default(); - - let map: Map = map![&env, (0, 0), (1, 10)]; - assert_eq!(map.get_unchecked(0), 0); - assert_eq!(map.get_unchecked(1), 10); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, MissingValue)")] - fn test_get_unchecked_panics_on_key_type_mismatch() { - let env = Env::default(); - - let map: Map = map![&env, (1i64.into_val(&env), 2i32.into_val(&env)),]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - let _ = map.get_unchecked(1); - } - - #[test] - #[should_panic(expected = "ConversionError")] - fn test_get_unchecked_panics_on_value_conversion() { - let env = Env::default(); - - let map: Map = map![&env, (1i32.into_val(&env), 2i64.into_val(&env)),]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - let _ = map.get_unchecked(1); - } - - #[test] - fn test_try_get_unchecked() { - let env = Env::default(); - - let map: Map = map![&env, (0, 0), (1, 10)]; - assert_eq!(map.get_unchecked(0), 0); - assert_eq!(map.get_unchecked(1), 10); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, MissingValue)")] - fn test_try_get_unchecked_panics_on_key_type_mismatch() { - let env = Env::default(); - - let map: Map = map![&env, (1i64.into_val(&env), 2i32.into_val(&env)),]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - let _ = map.try_get_unchecked(1); - } - - #[test] - fn test_try_get_unchecked_errors_on_value_conversion() { - let env = Env::default(); - - let map: Map = map![ - &env, - (1i32.into_val(&env), 2i32.into_val(&env)), - (3i32.into_val(&env), 4i64.into_val(&env)), - ]; - let map: Val = map.into(); - let map: Map = map.try_into_val(&env).unwrap(); - assert_eq!(map.try_get_unchecked(1), Ok(2)); - assert_eq!(map.try_get_unchecked(3), Err(ConversionError)); - } - - #[test] - fn test_remove() { - let env = Env::default(); - - let mut map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - - assert_eq!(map.len(), 5); - assert_eq!(map.get(2), Some(20)); - assert_eq!(map.remove(2), Some(())); - assert_eq!(map.get(2), None); - assert_eq!(map.len(), 4); - - // remove all items - map.remove(0); - map.remove(1); - map.remove(3); - map.remove(4); - assert_eq!(map![&env], map); - - // removing from empty map - let mut map: Map = map![&env]; - assert_eq!(map.remove(0), None); - assert_eq!(map.remove(u32::MAX), None); - } - - #[test] - fn test_remove_unchecked() { - let env = Env::default(); - - let mut map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - - assert_eq!(map.len(), 5); - assert_eq!(map.get(2), Some(20)); - map.remove_unchecked(2); - assert_eq!(map.get(2), None); - assert_eq!(map.len(), 4); - - // remove all items - map.remove_unchecked(0); - map.remove_unchecked(1); - map.remove_unchecked(3); - map.remove_unchecked(4); - assert_eq!(map![&env], map); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, MissingValue)")] - fn test_remove_unchecked_panic() { - let env = Env::default(); - let mut map: Map = map![&env, (0, 0), (1, 10), (2, 20), (3, 30), (4, 40)]; - map.remove_unchecked(100); // key does not exist - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs b/temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs deleted file mode 100644 index b858a31..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/muxed_address.rs +++ /dev/null @@ -1,416 +0,0 @@ -use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; - -use super::{ - env::internal::{AddressObject, Env as _, MuxedAddressObject, Tag}, - ConversionError, Env, TryFromVal, TryIntoVal, Val, -}; -use crate::{ - env::internal, - unwrap::{UnwrapInfallible, UnwrapOptimized}, - Address, Bytes, String, -}; - -#[cfg(not(target_family = "wasm"))] -use crate::env::internal::xdr::{ScAddress, ScVal}; - -#[derive(Clone)] -enum AddressObjectWrapper { - Address(AddressObject), - MuxedAddress(MuxedAddressObject), -} - -/// MuxedAddress is a union type that represents either the regular `Address`, -/// or a 'multiplexed' address that consists of a regular address and a u64 id -/// and can be used for representing the 'virtual' accounts that allows for -/// managing multiple balances off-chain with only a single on-chain balance -/// entry. The address part can be used as a regular `Address`, and the id -/// part should be used only in the events for the off-chain processing. -/// -/// This type is only necessary in a few special cases, such as token transfers -/// that support non-custodial accounts (e.g. for the exchange support). Prefer -/// using the regular `Address` type unless multiplexing support is necessary. -/// -/// This type is compatible with `Address` at the contract interface level, i.e. -/// if a contract accepts `MuxedAddress` as an input, then its callers may still -/// pass `Address` into the call successfully. This means that if a -/// contract has upgraded its interface to switch from `Address` argument to -/// `MuxedAddress` argument, it won't break any of its existing clients. -/// -/// Currently only the regular Stellar accounts can be multiplexed, i.e. -/// multiplexed contract addresses don't exist. -/// -/// Note, that multiplexed addresses can not be used directly as a storage key. -/// This is a precaution to prevent accidental unexpected fragmentation of -/// the key space (like creating an arbitrary number of balances for the same -/// actual `Address`). -#[derive(Clone)] -pub struct MuxedAddress { - env: Env, - obj: AddressObjectWrapper, -} - -impl Debug for MuxedAddress { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - #[cfg(target_family = "wasm")] - match &self.obj { - AddressObjectWrapper::Address(_) => write!(f, "Address(..)"), - AddressObjectWrapper::MuxedAddress(_) => write!(f, "MuxedAddress(..)"), - } - #[cfg(not(target_family = "wasm"))] - { - use crate::env::internal::xdr; - use stellar_strkey::Strkey; - match &self.obj { - AddressObjectWrapper::Address(address_object) => { - Address::try_from_val(self.env(), address_object) - .map_err(|_| core::fmt::Error)? - .fmt(f) - } - AddressObjectWrapper::MuxedAddress(muxed_address_object) => { - let sc_val = ScVal::try_from_val(self.env(), &muxed_address_object.to_val()) - .map_err(|_| core::fmt::Error)?; - if let ScVal::Address(addr) = sc_val { - match addr { - xdr::ScAddress::MuxedAccount(muxed_account) => { - let strkey = Strkey::MuxedAccountEd25519( - stellar_strkey::ed25519::MuxedAccount { - ed25519: muxed_account.ed25519.0, - id: muxed_account.id, - }, - ); - write!(f, "MuxedAccount({})", strkey.to_string()) - } - _ => Err(core::fmt::Error), - } - } else { - Err(core::fmt::Error) - } - } - } - } - } -} - -impl Eq for MuxedAddress {} - -impl PartialEq for MuxedAddress { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for MuxedAddress { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for MuxedAddress { - fn cmp(&self, other: &Self) -> Ordering { - let v = self - .env - .obj_cmp(self.to_val(), other.to_val()) - .unwrap_infallible(); - v.cmp(&0) - } -} - -impl TryFromVal for MuxedAddress { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &MuxedAddressObject) -> Result { - Ok(unsafe { MuxedAddress::unchecked_new(env.clone(), *val) }) - } -} - -impl TryFromVal for MuxedAddress { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &AddressObject) -> Result { - Ok(unsafe { MuxedAddress::unchecked_new_from_address(env.clone(), *val) }) - } -} - -impl TryFromVal for MuxedAddress { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - if val.get_tag() == Tag::AddressObject { - Ok(AddressObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } else { - Ok(MuxedAddressObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &MuxedAddress) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&MuxedAddress) -> Result { - Ok(v.to_val()) - } -} - -impl From<&MuxedAddress> for MuxedAddress { - fn from(address: &MuxedAddress) -> Self { - address.clone() - } -} - -impl From
for MuxedAddress { - fn from(address: Address) -> Self { - (&address).into() - } -} - -impl From<&Address> for MuxedAddress { - fn from(address: &Address) -> Self { - address - .as_object() - .try_into_val(address.env()) - .unwrap_infallible() - } -} - -impl MuxedAddress { - /// Creates a `MuxedAddress` corresponding to the provided Stellar strkey. - /// - /// Supported strkey types: - /// - Account address (G...) - /// - Muxed account address (M...) - /// - Contract address (C...) - /// - /// Any other strkey type will cause this to panic. - /// - /// Prefer using the `MuxedAddress` directly as input or output argument. Only - /// use this in special cases when addresses need to be shared between - /// different environments (e.g. different chains). - pub fn from_str(env: &Env, strkey: &str) -> MuxedAddress { - let strkey_string = String::from_str(env, strkey); - MuxedAddress::from_string(&strkey_string) - } - - /// Creates a `MuxedAddress` corresponding to the provided Stellar strkey. - /// - /// Supported strkey types: - /// - Account address (G...) - /// - Muxed account address (M...) - /// - Contract address (C...) - /// - /// Any other strkey type will cause this to panic. - /// - /// Prefer using the `MuxedAddress` directly as input or output argument. Only - /// use this in special cases when addresses need to be shared between - /// different environments (e.g. different chains). - pub fn from_string(strkey: &String) -> Self { - let env = strkey.env(); - let val = internal::Env::strkey_to_muxed_address(env, strkey.to_val()).unwrap_optimized(); - MuxedAddress::try_from_val(env, &val).unwrap_optimized() - } - - /// Creates a `MuxedAddress` corresponding to the provided Stellar strkey - /// in raw bytes form. - /// - /// Supported strkey types: - /// - Account address (G...) - /// - Muxed account address (M...) - /// - Contract address (C...) - /// - /// Any other strkey type will cause this to panic. - /// - /// Prefer using the `MuxedAddress` directly as input or output argument. Only - /// use this in special cases when addresses need to be shared between - /// different environments (e.g. different chains). - pub fn from_string_bytes(strkey: &Bytes) -> Self { - let env = strkey.env(); - let val = internal::Env::strkey_to_muxed_address(env, strkey.to_val()).unwrap_optimized(); - MuxedAddress::try_from_val(env, &val).unwrap_optimized() - } - - /// Returns the `Address` part of this multiplexed address. - /// - /// The address part is necessary to perform most of the operations, such - /// as authorization or storage. - pub fn address(&self) -> Address { - match &self.obj { - AddressObjectWrapper::Address(address_object) => { - Address::try_from_val(&self.env, address_object).unwrap_infallible() - } - AddressObjectWrapper::MuxedAddress(muxed_address_object) => Address::try_from_val( - &self.env, - &internal::Env::get_address_from_muxed_address(&self.env, *muxed_address_object) - .unwrap_infallible(), - ) - .unwrap_infallible(), - } - } - - /// Returns the multiplexing identifier part of this multiplexed address, - /// if any. - /// - /// Returns `None` for the regular (non-multiplexed) addresses. - /// - /// This identifier should normally be used in the events in order to allow - /// for tracking the virtual balances associated with this address off-chain. - pub fn id(&self) -> Option { - match &self.obj { - AddressObjectWrapper::Address(_) => None, - AddressObjectWrapper::MuxedAddress(muxed_address_object) => Some( - u64::try_from_val( - &self.env, - &internal::Env::get_id_from_muxed_address(&self.env, *muxed_address_object) - .unwrap_infallible(), - ) - .unwrap(), - ), - } - } - - #[inline(always)] - pub(crate) unsafe fn unchecked_new_from_address(env: Env, obj: AddressObject) -> Self { - Self { - env, - obj: AddressObjectWrapper::Address(obj), - } - } - - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: MuxedAddressObject) -> Self { - Self { - env, - obj: AddressObjectWrapper::MuxedAddress(obj), - } - } - - #[inline(always)] - pub fn env(&self) -> &Env { - &self.env - } - - pub fn as_val(&self) -> &Val { - match &self.obj { - AddressObjectWrapper::Address(o) => o.as_val(), - AddressObjectWrapper::MuxedAddress(o) => o.as_val(), - } - } - - pub fn to_val(&self) -> Val { - match self.obj { - AddressObjectWrapper::Address(o) => o.to_val(), - AddressObjectWrapper::MuxedAddress(o) => o.to_val(), - } - } - - /// Converts this address to its Stellar strkey representation. - /// - /// Returns: - /// - `G...` for account addresses - /// - `M...` for muxed account addresses - /// - `C...` for contract addresses - pub fn to_strkey(&self) -> String { - let s = internal::Env::muxed_address_to_strkey(&self.env, self.to_val()).unwrap_optimized(); - unsafe { String::unchecked_new(self.env.clone(), s) } - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&MuxedAddress> for ScVal { - fn from(v: &MuxedAddress) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.env, &v.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for ScVal { - fn from(v: MuxedAddress) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for MuxedAddress { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - let v = Val::try_from_val(env, val)?; - match val { - ScVal::Address(sc_address) => match sc_address { - ScAddress::Account(_) | ScAddress::Contract(_) => { - Ok(AddressObject::try_from_val(env, &v)? - .try_into_val(env) - .unwrap_infallible()) - } - ScAddress::MuxedAccount(_) => Ok(MuxedAddressObject::try_from_val(env, &v)? - .try_into_val(env) - .unwrap_infallible()), - ScAddress::ClaimableBalance(_) | ScAddress::LiquidityPool(_) => { - panic!("unsupported ScAddress type") - } - }, - _ => panic!("incorrect scval type"), - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for MuxedAddress { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScAddress) -> Result { - ScVal::Address(val.clone()).try_into_val(env) - } -} - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -impl crate::testutils::MuxedAddress for MuxedAddress { - fn generate(env: &Env) -> crate::MuxedAddress { - let sc_val = ScVal::Address(crate::env::internal::xdr::ScAddress::MuxedAccount( - crate::env::internal::xdr::MuxedEd25519Account { - ed25519: crate::env::internal::xdr::Uint256( - env.with_generator(|mut g| g.address()), - ), - id: env.with_generator(|mut g| g.mux_id()), - }, - )); - sc_val.try_into_val(env).unwrap() - } - - fn new>(address: T, id: u64) -> crate::MuxedAddress { - let address: MuxedAddress = address.into(); - let sc_val = ScVal::try_from_val(&address.env, address.as_val()).unwrap(); - let account_id = match sc_val { - ScVal::Address(address) => match address { - ScAddress::MuxedAccount(muxed_account) => muxed_account.ed25519, - ScAddress::Account(crate::env::internal::xdr::AccountId( - crate::env::internal::xdr::PublicKey::PublicKeyTypeEd25519(account_id), - )) => account_id, - ScAddress::Contract(_) => panic!("contract addresses can not be multiplexed"), - ScAddress::ClaimableBalance(_) | ScAddress::LiquidityPool(_) => unreachable!(), - }, - _ => unreachable!(), - }; - let result_sc_val = ScVal::Address(ScAddress::MuxedAccount( - crate::env::internal::xdr::MuxedEd25519Account { - id, - ed25519: account_id, - }, - )); - result_sc_val.try_into_val(&address.env).unwrap() - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/num.rs b/temp_sdk/soroban-sdk-26.0.1/src/num.rs deleted file mode 100644 index 011c96f..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/num.rs +++ /dev/null @@ -1,1123 +0,0 @@ -use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; - -use super::{ - env::internal::{ - DurationSmall, DurationVal, Env as _, I256Object, I256Small, I256Val, TimepointSmall, - TimepointVal, U256Object, U256Small, U256Val, - }, - Bytes, ConversionError, Env, TryFromVal, TryIntoVal, Val, -}; - -#[cfg(not(target_family = "wasm"))] -use crate::env::internal::xdr::ScVal; -use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; - -macro_rules! impl_num_wrapping_val_type { - ($wrapper:ident, $val:ty, $small:ty) => { - impl Debug for $wrapper { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - // FIXME: properly print it when we have the conversion functions - write!(f, "{:?}", self.val.as_val()) - } - } - - impl Eq for $wrapper {} - - impl PartialEq for $wrapper { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } - } - - impl PartialOrd for $wrapper { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } - } - - impl Ord for $wrapper { - fn cmp(&self, other: &Self) -> Ordering { - let self_raw = self.val.to_val(); - let other_raw = other.val.to_val(); - - match (<$small>::try_from(self_raw), <$small>::try_from(other_raw)) { - // Compare small numbers. - (Ok(self_num), Ok(other_num)) => self_num.cmp(&other_num), - // The object-to-small number comparisons are handled by `obj_cmp`, - // so it's safe to handle all the other cases using it. - _ => { - #[cfg(not(target_family = "wasm"))] - if !self.env.is_same_env(&other.env) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = self.env.obj_cmp(self_raw, other_raw).unwrap_infallible(); - v.cmp(&0) - } - } - } - } - - impl From<$wrapper> for $val { - #[inline(always)] - fn from(v: $wrapper) -> Self { - v.val - } - } - - impl From<&$wrapper> for $val { - #[inline(always)] - fn from(v: &$wrapper) -> Self { - v.val - } - } - - impl From<&$wrapper> for $wrapper { - #[inline(always)] - fn from(v: &$wrapper) -> Self { - v.clone() - } - } - - impl TryFromVal for $wrapper { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &$val) -> Result { - Ok(unsafe { $wrapper::unchecked_new(env.clone(), *val) }) - } - } - - impl TryFromVal for $wrapper { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(<$val>::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } - } - - impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &$wrapper) -> Result { - Ok(v.to_val()) - } - } - - impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&$wrapper) -> Result { - Ok(v.to_val()) - } - } - - #[cfg(not(target_family = "wasm"))] - impl From<&$wrapper> for ScVal { - fn from(v: &$wrapper) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - if let Ok(ss) = <$small>::try_from(v.val) { - ScVal::try_from(ss).unwrap() - } else { - ScVal::try_from_val(&v.env, &v.to_val()).unwrap() - } - } - } - - #[cfg(not(target_family = "wasm"))] - impl From<$wrapper> for ScVal { - fn from(v: $wrapper) -> Self { - (&v).into() - } - } - - #[cfg(not(target_family = "wasm"))] - impl TryFromVal for $wrapper { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok(<$val>::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible()) - } - } - - impl $wrapper { - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, val: $val) -> Self { - Self { env, val } - } - - /// Converts a `Val` known to be of this type into `Self` without - /// env-based conversion. The caller must guarantee the `Val` is of - /// the correct type; only a cheap tag check is performed. - #[inline(always)] - pub(crate) unsafe fn unchecked_from_val(env: Env, val: Val) -> Self { - Self { - env, - val: <$val>::try_from(val).unwrap_optimized(), - } - } - - #[inline(always)] - pub fn env(&self) -> &Env { - &self.env - } - - pub fn as_val(&self) -> &Val { - self.val.as_val() - } - - pub fn to_val(&self) -> Val { - self.val.to_val() - } - - pub fn to_val_type(&self) -> $val { - self.val - } - } - }; -} - -/// U256 holds a 256-bit unsigned integer. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{U256, Env}; -/// -/// let env = Env::default(); -/// let u1 = U256::from_u32(&env, 6); -/// let u2 = U256::from_u32(&env, 3); -/// assert_eq!(u1.add(&u2), U256::from_u32(&env, 9)); -/// ``` -#[derive(Clone)] -pub struct U256 { - env: Env, - val: U256Val, -} - -impl_num_wrapping_val_type!(U256, U256Val, U256Small); - -impl U256 { - pub const BITS: u32 = 256; - - /// Returns the smallest value that can be represented by this type (0). - pub fn min_value(env: &Env) -> Self { - Self::from_u32(env, 0) - } - - /// Returns the largest value that can be represented by this type (2^256 - 1). - pub fn max_value(env: &Env) -> Self { - Self::from_parts(env, u64::MAX, u64::MAX, u64::MAX, u64::MAX) - } - - fn is_zero(&self) -> bool { - *self == U256::from_u32(&self.env, 0) - } - - pub fn from_u32(env: &Env, u: u32) -> Self { - U256 { - env: env.clone(), - val: U256Val::from_u32(u), - } - } - - pub fn from_u128(env: &Env, u: u128) -> Self { - let lo_hi = (u >> 64) as u64; - let lo_lo = u as u64; - Self::from_parts(env, 0, 0, lo_hi, lo_lo) - } - - pub fn from_parts(env: &Env, hi_hi: u64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self { - let obj = env - .obj_from_u256_pieces(hi_hi, hi_lo, lo_hi, lo_lo) - .unwrap_infallible(); - U256 { - env: env.clone(), - val: obj.into(), - } - } - - pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self { - let val = env - .u256_val_from_be_bytes(bytes.to_object()) - .unwrap_infallible(); - U256 { - env: env.clone(), - val, - } - } - - pub fn to_u128(&self) -> Option { - let v = *self.val.as_val(); - - // If v is U256Small it can be converted directly - if let Ok(small) = U256Small::try_from(v) { - return Some(u64::from(small) as u128); - } - - // Otherwise use U256Object and take low sections if high are empty - let obj: U256Object = v.try_into().ok()?; - let hi_hi = self.env.obj_to_u256_hi_hi(obj).unwrap_infallible(); - let hi_lo = self.env.obj_to_u256_hi_lo(obj).unwrap_infallible(); - if hi_hi != 0 || hi_lo != 0 { - return None; - } - let lo_hi = self.env.obj_to_u256_lo_hi(obj).unwrap_infallible(); - let lo_lo = self.env.obj_to_u256_lo_lo(obj).unwrap_infallible(); - Some(((lo_hi as u128) << 64) | (lo_lo as u128)) - } - - pub fn to_be_bytes(&self) -> Bytes { - let obj = self - .env - .u256_val_to_be_bytes(self.to_val_type()) - .unwrap_infallible(); - unsafe { Bytes::unchecked_new(self.env.clone(), obj) } - } - - pub fn add(&self, other: &U256) -> U256 { - let val = self.env.u256_add(self.val, other.val).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn sub(&self, other: &U256) -> U256 { - let val = self.env.u256_sub(self.val, other.val).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn mul(&self, other: &U256) -> U256 { - let val = self.env.u256_mul(self.val, other.val).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn div(&self, other: &U256) -> U256 { - let val = self.env.u256_div(self.val, other.val).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn rem_euclid(&self, other: &U256) -> U256 { - let val = self - .env - .u256_rem_euclid(self.val, other.val) - .unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn pow(&self, pow: u32) -> U256 { - let val = self.env.u256_pow(self.val, pow.into()).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn shl(&self, bits: u32) -> U256 { - let val = self.env.u256_shl(self.val, bits.into()).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - pub fn shr(&self, bits: u32) -> U256 { - let val = self.env.u256_shr(self.val, bits.into()).unwrap_infallible(); - U256 { - env: self.env.clone(), - val, - } - } - - /// Performs checked addition. Returns `None` if overflow occurred. - pub fn checked_add(&self, other: &U256) -> Option { - let val = self - .env - .u256_checked_add(self.val, other.val) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked subtraction. Returns `None` if overflow occurred. - pub fn checked_sub(&self, other: &U256) -> Option { - let val = self - .env - .u256_checked_sub(self.val, other.val) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked multiplication. Returns `None` if overflow occurred. - pub fn checked_mul(&self, other: &U256) -> Option { - let val = self - .env - .u256_checked_mul(self.val, other.val) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked exponentiation. Returns `None` if overflow occurred. - pub fn checked_pow(&self, pow: u32) -> Option { - let val = self - .env - .u256_checked_pow(self.val, pow.into()) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { U256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked division. Returns `None` if `other` is zero. - pub fn checked_div(&self, other: &U256) -> Option { - if other.is_zero() { - return None; - } - Some(self.div(other)) - } - - /// Performs checked Euclidean remainder. Returns `None` if `other` is zero. - pub fn checked_rem_euclid(&self, other: &U256) -> Option { - if other.is_zero() { - return None; - } - Some(self.rem_euclid(other)) - } - - /// Performs checked left shift. Returns `None` if `bits >= 256`. - pub fn checked_shl(&self, bits: u32) -> Option { - if bits >= Self::BITS { - return None; - } - Some(self.shl(bits)) - } - - /// Performs checked right shift. Returns `None` if `bits >= 256`. - pub fn checked_shr(&self, bits: u32) -> Option { - if bits >= Self::BITS { - return None; - } - Some(self.shr(bits)) - } -} - -/// I256 holds a 256-bit signed integer. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{I256, Env}; -/// -/// let env = Env::default(); -/// -/// let i1 = I256::from_i32(&env, -6); -/// let i2 = I256::from_i32(&env, 3); -/// assert_eq!(i1.add(&i2), I256::from_i32(&env, -3)); -/// ``` -#[derive(Clone)] -pub struct I256 { - env: Env, - val: I256Val, -} - -impl_num_wrapping_val_type!(I256, I256Val, I256Small); - -impl I256 { - pub const BITS: u32 = 256; - - /// Returns the smallest value that can be represented by this type (-2^255). - pub fn min_value(env: &Env) -> Self { - Self::from_parts(env, i64::MIN, 0, 0, 0) - } - - /// Returns the largest value that can be represented by this type (2^255 - 1). - pub fn max_value(env: &Env) -> Self { - Self::from_parts(env, i64::MAX, u64::MAX, u64::MAX, u64::MAX) - } - - fn is_zero(&self) -> bool { - *self == I256::from_i32(&self.env, 0) - } - - fn is_neg_one(&self) -> bool { - *self == I256::from_i32(&self.env, -1) - } - - pub fn from_i32(env: &Env, i: i32) -> Self { - I256 { - env: env.clone(), - val: I256Val::from_i32(i), - } - } - - pub fn from_i128(env: &Env, i: i128) -> Self { - let lo_hi = (i >> 64) as u64; - let lo_lo = i as u64; - let (hi_hi, hi_lo) = if i < 0 { - (-1_i64, u64::MAX) // sign extend 1 bit - } else { - (0_i64, 0_u64) // sign extend 0 bit - }; - I256::from_parts(env, hi_hi, hi_lo, lo_hi, lo_lo) - } - - pub fn from_parts(env: &Env, hi_hi: i64, hi_lo: u64, lo_hi: u64, lo_lo: u64) -> Self { - let obj = env - .obj_from_i256_pieces(hi_hi, hi_lo, lo_hi, lo_lo) - .unwrap_infallible(); - I256 { - env: env.clone(), - val: obj.into(), - } - } - - pub fn from_be_bytes(env: &Env, bytes: &Bytes) -> Self { - let val = env - .i256_val_from_be_bytes(bytes.to_object()) - .unwrap_infallible(); - I256 { - env: env.clone(), - val, - } - } - - pub fn to_i128(&self) -> Option { - let v = *self.val.as_val(); - - // If v is I256Small it can be converted directly - if let Ok(small) = I256Small::try_from(v) { - return Some(i64::from(small) as i128); - } - - // Otherwise use I256Object and take low sections if high are either - // all 1 bits or all 0 bits (negative and positive respectively) - let obj: I256Object = v.try_into().ok()?; - let hi_hi = self.env.obj_to_i256_hi_hi(obj).unwrap_infallible(); - let hi_lo = self.env.obj_to_i256_hi_lo(obj).unwrap_infallible(); - let lo_hi = self.env.obj_to_i256_lo_hi(obj).unwrap_infallible(); - let lo_lo = self.env.obj_to_i256_lo_lo(obj).unwrap_infallible(); - // The low 128 bits as an i128 - let lo = (((lo_hi as u128) << 64) | (lo_lo as u128)) as i128; - - if lo < 0 && hi_hi == -1 && hi_lo == u64::MAX { - Some(lo) // if negative low, then high must be all 1 bit - } else if 0 <= lo && hi_hi == 0 && hi_lo == 0 { - Some(lo) // if non-negative low, then high must be all 0 bit - } else { - None - } - } - - pub fn to_be_bytes(&self) -> Bytes { - let obj = self - .env - .i256_val_to_be_bytes(self.to_val_type()) - .unwrap_infallible(); - unsafe { Bytes::unchecked_new(self.env.clone(), obj) } - } - - pub fn add(&self, other: &I256) -> I256 { - let val = self.env.i256_add(self.val, other.val).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn sub(&self, other: &I256) -> I256 { - let val = self.env.i256_sub(self.val, other.val).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn mul(&self, other: &I256) -> I256 { - let val = self.env.i256_mul(self.val, other.val).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn div(&self, other: &I256) -> I256 { - let val = self.env.i256_div(self.val, other.val).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn rem_euclid(&self, other: &I256) -> I256 { - let val = self - .env - .i256_rem_euclid(self.val, other.val) - .unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn pow(&self, pow: u32) -> I256 { - let val = self.env.i256_pow(self.val, pow.into()).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn shl(&self, bits: u32) -> I256 { - let val = self.env.i256_shl(self.val, bits.into()).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - pub fn shr(&self, bits: u32) -> I256 { - let val = self.env.i256_shr(self.val, bits.into()).unwrap_infallible(); - I256 { - env: self.env.clone(), - val, - } - } - - /// Performs checked addition. Returns `None` if overflow occurred. - pub fn checked_add(&self, other: &I256) -> Option { - let val = self - .env - .i256_checked_add(self.val, other.val) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked subtraction. Returns `None` if overflow occurred. - pub fn checked_sub(&self, other: &I256) -> Option { - let val = self - .env - .i256_checked_sub(self.val, other.val) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked multiplication. Returns `None` if overflow occurred. - pub fn checked_mul(&self, other: &I256) -> Option { - let val = self - .env - .i256_checked_mul(self.val, other.val) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Performs checked exponentiation. Returns `None` if overflow occurred. - pub fn checked_pow(&self, pow: u32) -> Option { - let val = self - .env - .i256_checked_pow(self.val, pow.into()) - .unwrap_infallible(); - if val.is_void() { - None - } else { - Some(unsafe { I256::unchecked_from_val(self.env.clone(), val) }) - } - } - - /// Returns `true` if dividing `self` by `other` would overflow or divide by zero. - /// This covers: `other == 0`, or `self == I256::MIN && other == -1`. - fn is_div_overflow(&self, other: &I256) -> bool { - if other.is_zero() { - return true; - } - if other.is_neg_one() { - let min = I256::min_value(&self.env); - if *self == min { - return true; - } - } - false - } - - /// Performs checked division. Returns `None` if `other` is zero, or if - /// `self` is `I256::MIN` and `other` is `-1` (overflow). - pub fn checked_div(&self, other: &I256) -> Option { - if self.is_div_overflow(other) { - return None; - } - Some(self.div(other)) - } - - /// Performs checked Euclidean remainder. Returns `None` if `other` is zero, - /// or if `self` is `I256::MIN` and `other` is `-1` (overflow in intermediate - /// division). - pub fn checked_rem_euclid(&self, other: &I256) -> Option { - if self.is_div_overflow(other) { - return None; - } - Some(self.rem_euclid(other)) - } - - /// Performs checked left shift. Returns `None` if `bits >= 256`. - pub fn checked_shl(&self, bits: u32) -> Option { - if bits >= Self::BITS { - return None; - } - Some(self.shl(bits)) - } - - /// Performs checked right shift. Returns `None` if `bits >= 256`. - pub fn checked_shr(&self, bits: u32) -> Option { - if bits >= Self::BITS { - return None; - } - Some(self.shr(bits)) - } -} - -#[doc = "Timepoint holds a 64-bit unsigned integer."] -#[derive(Clone)] -pub struct Timepoint { - env: Env, - val: TimepointVal, -} - -impl_num_wrapping_val_type!(Timepoint, TimepointVal, TimepointSmall); - -impl Timepoint { - /// Create a Timepoint from a unix time in seconds, the time in seconds - /// since January 1, 1970 UTC. - pub fn from_unix(env: &Env, seconds: u64) -> Timepoint { - let val = TimepointVal::try_from_val(env, &seconds).unwrap_optimized(); - Timepoint { - env: env.clone(), - val, - } - } - - /// Returns the Timepoint as unix time in seconds, the time in seconds since - /// January 1, 1970 UTC. - pub fn to_unix(&self) -> u64 { - u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized() - } -} - -#[doc = "Duration holds a 64-bit unsigned integer."] -#[derive(Clone)] -pub struct Duration { - env: Env, - val: DurationVal, -} - -impl_num_wrapping_val_type!(Duration, DurationVal, DurationSmall); - -impl Duration { - /// Create a Duration from seconds. - pub fn from_seconds(env: &Env, seconds: u64) -> Duration { - let val = DurationVal::try_from_val(env, &seconds).unwrap_optimized(); - Duration { - env: env.clone(), - val, - } - } - - /// Returns the Duration as seconds. - pub fn to_seconds(&self) -> u64 { - u64::try_from_val(self.env(), &self.to_val_type()).unwrap_optimized() - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_u256_roundtrip() { - let env = Env::default(); - - let u1 = U256::from_u32(&env, 12345); - let bytes = u1.to_be_bytes(); - let u2 = U256::from_be_bytes(&env, &bytes); - assert_eq!(u1, u2); - } - - #[test] - fn test_u256_u128_conversion() { - let env = Env::default(); - - // positive - let start = u128::MAX / 7; - let from = U256::from_u128(&env, start); - let end = from.to_u128().unwrap(); - assert_eq!(start, end); - - let over_u128 = from.mul(&U256::from_u32(&env, 8)); - let failure = over_u128.to_u128(); - assert_eq!(failure, None); - - // zero - let start = 0_u128; - let from = U256::from_u128(&env, start); - let end = from.to_u128().unwrap(); - assert_eq!(start, end); - - // small (exercises the U256Small fast-path in to_u128) - let from_small = U256::from_u32(&env, 0); - assert_eq!(from_small.to_u128(), Some(0_u128)); - - let from_small = U256::from_u32(&env, u32::MAX); - assert_eq!(from_small.to_u128(), Some(u32::MAX as u128)); - } - - #[test] - fn test_i256_roundtrip() { - let env = Env::default(); - - let i1 = I256::from_i32(&env, -12345); - let bytes = i1.to_be_bytes(); - let i2 = I256::from_be_bytes(&env, &bytes); - assert_eq!(i1, i2); - } - - #[test] - fn test_i256_i128_conversion() { - let env = Env::default(); - - // positive - let start = i128::MAX / 7; - let from = I256::from_i128(&env, start); - let end = from.to_i128().unwrap(); - assert_eq!(start, end); - - let over_i128 = from.mul(&I256::from_i32(&env, 8)); - let failure = over_i128.to_i128(); - assert_eq!(failure, None); - - // negative - let start = i128::MIN / 7; - let from = I256::from_i128(&env, start); - let end = from.to_i128().unwrap(); - assert_eq!(start, end); - - let over_i128 = from.mul(&I256::from_i32(&env, 8)); - let failure = over_i128.to_i128(); - assert_eq!(failure, None); - - // zero - let start = 0_i128; - let from = I256::from_i128(&env, start); - let end = from.to_i128().unwrap(); - assert_eq!(start, end); - - // small (exercises the I256Small fast-path in to_i128) - let from_small = I256::from_i32(&env, 0); - assert_eq!(from_small.to_i128(), Some(0_i128)); - - let from_small = I256::from_i32(&env, i32::MAX); - assert_eq!(from_small.to_i128(), Some(i32::MAX as i128)); - - let from_small = I256::from_i32(&env, i32::MIN); - assert_eq!(from_small.to_i128(), Some(i32::MIN as i128)); - } - - #[test] - fn test_timepoint_roundtrip() { - let env = Env::default(); - - let tp = Timepoint::from_unix(&env, 123); - let u = tp.to_unix(); - assert_eq!(u, 123); - } - - #[test] - fn test_duration_roundtrip() { - let env = Env::default(); - - let tp = Duration::from_seconds(&env, 123); - let u = tp.to_seconds(); - assert_eq!(u, 123); - } - - #[test] - fn test_u256_arith() { - let env = Env::default(); - - let u1 = U256::from_u32(&env, 6); - let u2 = U256::from_u32(&env, 3); - assert_eq!(u1.add(&u2), U256::from_u32(&env, 9)); - assert_eq!(u1.sub(&u2), U256::from_u32(&env, 3)); - assert_eq!(u1.mul(&u2), U256::from_u32(&env, 18)); - assert_eq!(u1.div(&u2), U256::from_u32(&env, 2)); - assert_eq!(u1.pow(2), U256::from_u32(&env, 36)); - assert_eq!(u1.shl(2), U256::from_u32(&env, 24)); - assert_eq!(u1.shr(1), U256::from_u32(&env, 3)); - - let u3 = U256::from_u32(&env, 7); - let u4 = U256::from_u32(&env, 4); - assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3)); - } - - #[test] - fn test_u256_min() { - let env = Env::default(); - - let min = U256::min_value(&env); - assert_eq!(min, U256::from_u32(&env, 0)); - - let one = U256::from_u32(&env, 1); - assert_eq!(min.checked_sub(&one), None); - assert!(min.checked_add(&one).is_some()); - } - - #[test] - fn test_u256_max() { - let env = Env::default(); - - let max = U256::max_value(&env); - assert_eq!( - max, - U256::from_parts(&env, u64::MAX, u64::MAX, u64::MAX, u64::MAX) - ); - - let u128_max = U256::from_u128(&env, u128::MAX); - assert!(max > u128_max); - - let one = U256::from_u32(&env, 1); - assert_eq!(max.checked_add(&one), None); - assert!(max.checked_sub(&one).is_some()); - } - - #[test] - fn test_u256_checked_arith() { - let env = Env::default(); - - let u1 = U256::from_u32(&env, 6); - let u2 = U256::from_u32(&env, 3); - assert_eq!(u1.checked_add(&u2), Some(U256::from_u32(&env, 9))); - assert_eq!(u1.checked_sub(&u2), Some(U256::from_u32(&env, 3))); - assert_eq!(u1.checked_mul(&u2), Some(U256::from_u32(&env, 18))); - assert_eq!(u1.checked_div(&u2), Some(U256::from_u32(&env, 2))); - assert_eq!(u1.checked_pow(2), Some(U256::from_u32(&env, 36))); - assert_eq!(u1.checked_shl(2), Some(U256::from_u32(&env, 24))); - assert_eq!(u1.checked_shr(1), Some(U256::from_u32(&env, 3))); - - let u3 = U256::from_u32(&env, 7); - let u4 = U256::from_u32(&env, 4); - assert_eq!(u3.checked_rem_euclid(&u4), Some(U256::from_u32(&env, 3))); - } - - #[test] - fn test_u256_checked_arith_overflow() { - let env = Env::default(); - - let zero = U256::from_u32(&env, 0); - let one = U256::from_u32(&env, 1); - let two = U256::from_u32(&env, 2); - let max = U256::max_value(&env); - assert_eq!(max.checked_add(&one), None); - assert_eq!(zero.checked_sub(&one), None); - assert_eq!(max.checked_mul(&two), None); - assert_eq!(one.checked_div(&zero), None); - assert_eq!(max.checked_pow(2), None); - assert_eq!(one.checked_shl(256), None); - assert_eq!(one.checked_shr(256), None); - assert_eq!(one.checked_rem_euclid(&zero), None); - - let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0); - let one_from_parts = U256::from_parts(&env, 0, 0, 0, 1); - assert_eq!(one.checked_div(&zero_from_parts), None); - assert_eq!(zero.checked_sub(&one_from_parts), None); - } - - #[test] - fn test_u256_is_zero() { - let env = Env::default(); - - let zero = U256::from_u32(&env, 0); - let zero_from_parts = U256::from_parts(&env, 0, 0, 0, 0); - let non_zero = U256::from_u32(&env, 1); - - assert!(zero.is_zero()); - assert!(zero_from_parts.is_zero()); - assert!(!non_zero.is_zero()); - } - - #[test] - fn test_i256_arith() { - let env = Env::default(); - - let i1 = I256::from_i32(&env, -6); - let i2 = I256::from_i32(&env, 3); - assert_eq!(i1.add(&i2), I256::from_i32(&env, -3)); - assert_eq!(i1.sub(&i2), I256::from_i32(&env, -9)); - assert_eq!(i1.mul(&i2), I256::from_i32(&env, -18)); - assert_eq!(i1.div(&i2), I256::from_i32(&env, -2)); - assert_eq!(i1.pow(2), I256::from_i32(&env, 36)); - assert_eq!(i1.shl(2), I256::from_i32(&env, -24)); - assert_eq!(i1.shr(1), I256::from_i32(&env, -3)); - - let u3 = I256::from_i32(&env, -7); - let u4 = I256::from_i32(&env, 4); - assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1)); - } - - #[test] - fn test_i256_min() { - let env = Env::default(); - - let min = I256::min_value(&env); - assert_eq!(min, I256::from_parts(&env, i64::MIN, 0, 0, 0)); - - let i128_min = I256::from_i128(&env, i128::MIN); - assert!(min < i128_min); - - let one = I256::from_i32(&env, 1); - assert_eq!(min.checked_sub(&one), None); - assert!(min.checked_add(&one).is_some()); - } - - #[test] - fn test_i256_max() { - let env = Env::default(); - - let max = I256::max_value(&env); - assert_eq!( - max, - I256::from_parts(&env, i64::MAX, u64::MAX, u64::MAX, u64::MAX) - ); - - let i128_max = I256::from_i128(&env, i128::MAX); - assert!(max > i128_max); - - let one = I256::from_i32(&env, 1); - assert_eq!(max.checked_add(&one), None); - assert!(max.checked_sub(&one).is_some()); - } - - #[test] - fn test_i256_checked_arith() { - let env = Env::default(); - - let i1 = I256::from_i32(&env, -6); - let i2 = I256::from_i32(&env, 3); - assert_eq!(i1.checked_add(&i2), Some(I256::from_i32(&env, -3))); - assert_eq!(i1.checked_sub(&i2), Some(I256::from_i32(&env, -9))); - assert_eq!(i1.checked_mul(&i2), Some(I256::from_i32(&env, -18))); - assert_eq!(i1.checked_div(&i2), Some(I256::from_i32(&env, -2))); - assert_eq!(i1.checked_pow(2), Some(I256::from_i32(&env, 36))); - assert_eq!(i1.checked_shl(2), Some(I256::from_i32(&env, -24))); - assert_eq!(i1.checked_shr(1), Some(I256::from_i32(&env, -3))); - - let u3 = I256::from_i32(&env, -7); - let u4 = I256::from_i32(&env, 4); - assert_eq!(u3.checked_rem_euclid(&u4), Some(I256::from_i32(&env, 1))); - } - - #[test] - fn test_i256_checked_arith_overflow() { - let env = Env::default(); - - let zero = I256::from_i32(&env, 0); - let one = I256::from_i32(&env, 1); - let negative_one = I256::from_i32(&env, -1); - let two = I256::from_i32(&env, 2); - let max = I256::max_value(&env); - let min = I256::min_value(&env); - assert_eq!(max.checked_add(&one), None); - assert_eq!(min.checked_sub(&one), None); - assert_eq!(max.checked_mul(&two), None); - assert_eq!(one.checked_div(&zero), None); - assert_eq!(min.checked_div(&negative_one), None); - assert_eq!(max.checked_pow(2), None); - assert_eq!(one.checked_shl(256), None); - assert_eq!(one.checked_shr(256), None); - assert_eq!(one.checked_rem_euclid(&zero), None); - - let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0); - let one_from_parts = I256::from_parts(&env, 0, 0, 0, 1); - assert_eq!(one.checked_div(&zero_from_parts), None); - assert_eq!(min.checked_sub(&one_from_parts), None); - } - - #[test] - fn test_i256_is_zero() { - let env = Env::default(); - - let zero = I256::from_i32(&env, 0); - let zero_from_parts = I256::from_parts(&env, 0, 0, 0, 0); - let non_zero = I256::from_i32(&env, 1); - - assert!(zero.is_zero()); - assert!(zero_from_parts.is_zero()); - assert!(!non_zero.is_zero()); - } - - #[test] - fn test_i256_is_neg_one() { - let env = Env::default(); - - let negative_one = I256::from_i32(&env, -1); - let negative_one_from_parts = I256::from_parts(&env, -1, u64::MAX, u64::MAX, u64::MAX); - let negative_two = I256::from_i32(&env, -2); - - assert!(negative_one.is_neg_one()); - assert!(negative_one_from_parts.is_neg_one()); - assert!(!negative_two.is_neg_one()); - } - - #[test] - fn test_i256_is_div_overflow() { - let env = Env::default(); - - let zero = I256::from_i32(&env, 0); - let negative_one = I256::from_i32(&env, -1); - let min = I256::min_value(&env); - - assert!(!zero.is_div_overflow(&negative_one)); - - assert!(negative_one.is_div_overflow(&zero)); - assert!(min.is_div_overflow(&negative_one)); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/prng.rs b/temp_sdk/soroban-sdk-26.0.1/src/prng.rs deleted file mode 100644 index cf28a07..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/prng.rs +++ /dev/null @@ -1,586 +0,0 @@ -//! Prng contains a pseudo-random number generator. -//! -//! ## Warning -//! -//! Do not use the PRNG in this module without a clear understanding of two -//! major limitations in the way it is deployed in the Stellar network: -//! -//! 1. The PRNG is seeded with data that is public as soon as each ledger is -//! nominated. Therefore it **should never be used to generate secrets**. -//! -//! 2. The PRNG is seeded with data that is under the control of validators. -//! Therefore it **should only be used in applications where the risk of -//! validator influence is acceptable**. -//! -//! The PRNG in this module is a strong CSPRNG (ChaCha20) and can be manually -//! re-seeded by contracts, in order to support commit/reveal schemes, oracles, -//! or similar advanced types of pseudo-random contract behaviour. Any PRNG is -//! however only as strong as its seed. -//! -//! The network runs in strict consensus, so every node in the network seeds its -//! PRNG with a consensus value, **not a random entropy source**. It uses data -//! that is generally difficult to predict in advance, and generally difficult -//! for network **users** to bias to a specific value: the seed is derived from -//! the overall transaction-set hash and the hash-sorted position number of each -//! transaction within it. But this seed is **not secret** and **not -//! cryptographically hard to bias** if a corrupt **validator** were to choose -//! to do so (similar to the way a corrupt validator can bias overall -//! transaction admission in the network). -//! -//! In other words the network will provide a stronger seed than a contract -//! could likely derive on-chain using any other public data visible to it (eg. -//! better than using a timestamp, ledger number, counter, or a similarly weak -//! seed) but weaker than a contract could acquire using a commit/reveal scheme -//! with an off-chain source of trusted random entropy. -//! -//! You should carefully consider whether these limitations are acceptable for -//! your application before using this module. -//! -//! ## Operation -//! -//! The host has a single hidden "base" PRNG that is seeded by the network. The -//! base PRNG is then used to seed separate, independent "local" PRNGs for each -//! contract invocation. This independence has the following characteristics: -//! -//! - Contract invocations can only access (use or reseed) their local PRNG. -//! - Contract invocations cannot influence any other invocation's local PRNG, -//! except by influencing the other invocation to make a call to its PRNG. -//! - Contracts cannot influence the base PRNG that seeds local PRNGs, except -//! by making calls and thereby creating new local PRNGs with new seeds. -//! - A contract invocation's local PRNG maintains state through the life of -//! the invocation. -//! - That state is advanced by each call from the invocation to a PRNG -//! function in this module. -//! - A contract invocation's local PRNG is destroyed after the invocation. -//! - Any re-entry of a contract counts as a separate invocation. -//! -//! ## Testing -//! -//! In local tests, the base PRNG of each host is seeded to zero when the host -//! is constructed, so each contract invocation's local PRNG seed (and all its -//! PRNG-derived calls) will be determined strictly by its order of invocation -//! in the test. Assuming this order is stable, each test run should see stable -//! output from the local PRNG. -use core::ops::{Bound, RangeBounds}; - -use crate::{ - env::internal, - unwrap::{UnwrapInfallible, UnwrapOptimized}, - Bytes, BytesN, Env, IntoVal, Vec, -}; - -/// Prng is a pseudo-random generator. -/// -/// # Warning -/// -/// **The PRNG is unsuitable for generating secrets or use in applications with -/// low risk tolerance, see the module-level comment.** -pub struct Prng { - env: Env, -} - -impl Prng { - pub(crate) fn new(env: &Env) -> Prng { - Prng { env: env.clone() } - } - - pub fn env(&self) -> &Env { - &self.env - } - - /// Reseeds the PRNG with the provided value. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - pub fn seed(&self, seed: Bytes) { - let env = self.env(); - debug_assert_in_contract!(env); - internal::Env::prng_reseed(env, seed.into()).unwrap_infallible(); - } - - /// Fills the type with a random value. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - /// - /// # Examples - /// - /// ## `u64` - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// let mut value: u64 = 0; - /// env.prng().fill(&mut value); - /// assert_eq!(value, 8478755077819529274); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - /// - /// ## `[u8]` - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// let mut value = [0u8; 32]; - /// env.prng().fill(&mut value); - /// assert_eq!( - /// value, - /// [ - /// 58, 248, 248, 38, 210, 150, 170, 117, 122, 110, 9, 101, 244, 57, - /// 221, 102, 164, 48, 43, 104, 222, 229, 242, 29, 25, 148, 88, 204, - /// 130, 148, 2, 66 - /// ], - /// ); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - pub fn fill(&self, v: &mut T) - where - T: Fill + ?Sized, - { - v.fill(self); - } - - /// Returns a random value of the given type. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - /// - /// # Examples - /// - /// ## `u64` - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// let value: u64 = env.prng().gen(); - /// assert_eq!(value, 8478755077819529274); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - /// - /// ## `[u8; N]` - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// let value: [u8; 32] = env.prng().gen(); - /// assert_eq!( - /// value, - /// [ - /// 58, 248, 248, 38, 210, 150, 170, 117, 122, 110, 9, 101, 244, 57, - /// 221, 102, 164, 48, 43, 104, 222, 229, 242, 29, 25, 148, 88, 204, - /// 130, 148, 2, 66 - /// ], - /// ); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - pub fn gen(&self) -> T - where - T: Gen, - { - T::gen(self) - } - - /// Returns a random value of the given type with the given length. - /// - /// # Panics - /// - /// If the length is greater than u32::MAX. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - /// - /// # Examples - /// - /// ## `Bytes` - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// // Get a value of length 32 bytes. - /// let value: Bytes = env.prng().gen_len(32); - /// assert_eq!(value, Bytes::from_slice( - /// &env, - /// &[ - /// 58, 248, 248, 38, 210, 150, 170, 117, 122, 110, 9, 101, 244, 57, - /// 221, 102, 164, 48, 43, 104, 222, 229, 242, 29, 25, 148, 88, 204, - /// 130, 148, 2, 66 - /// ], - /// )); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - pub fn gen_len(&self, len: T::Len) -> T - where - T: GenLen, - { - T::gen_len(self, len) - } - - /// Returns a random value of the given type in the range specified. - /// - /// # Panics - /// - /// If the start of the range is greater than the end. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - /// - /// # Examples - /// - /// ## `u64` - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// // Get a value in the range of 1 to 100, inclusive. - /// let value: u64 = env.prng().gen_range(1..=100); - /// assert_eq!(value, 46); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - pub fn gen_range(&self, r: impl RangeBounds) -> T - where - T: GenRange, - { - T::gen_range(self, r) - } - - /// Returns a random u64 in the range specified. - /// - /// # Panics - /// - /// If the range is empty. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - /// - /// # Examples - /// - /// ``` - /// # use soroban_sdk::{Env, contract, contractimpl, symbol_short, Bytes}; - /// # - /// # #[contract] - /// # pub struct Contract; - /// # - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// # let contract_id = env.register(Contract, ()); - /// # env.as_contract(&contract_id, || { - /// # env.prng().seed(Bytes::from_array(&env, &[1; 32])); - /// // Get a value in the range of 1 to 100, inclusive. - /// let value = env.prng().u64_in_range(1..=100); - /// assert_eq!(value, 46); - /// # }) - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - #[deprecated(note = "use env.prng().gen_range(...)")] - pub fn u64_in_range(&self, r: impl RangeBounds) -> u64 { - self.gen_range(r) - } - - /// Shuffles a value using the Fisher-Yates algorithm. - /// - /// # Warning - /// - /// **The PRNG is unsuitable for generating secrets or use in applications with - /// low risk tolerance, see the module-level comment.** - pub fn shuffle(&self, v: &mut T) - where - T: Shuffle, - { - v.shuffle(self); - } -} - -impl Shuffle for Vec { - fn shuffle(&mut self, prng: &Prng) { - let env = prng.env(); - debug_assert_in_contract!(env); - let obj = internal::Env::prng_vec_shuffle(env, self.to_object()).unwrap_infallible(); - *self = unsafe { Self::unchecked_new(env.clone(), obj) }; - } -} - -/// Implemented by types that support being filled by a Prng. -pub trait Fill { - /// Fills the given value with the Prng. - fn fill(&mut self, prng: &Prng); -} - -/// Implemented by types that support being generated by a Prng. -pub trait Gen { - /// Generates a value of the implementing type with the Prng. - fn gen(prng: &Prng) -> Self; -} - -/// Implemented by types that support being generated of specific length by a -/// Prng. -pub trait GenLen { - type Len; - - /// Generates a value of the given implementing type with length with the - /// Prng. - /// - /// # Panics - /// - /// If the length is greater than u32::MAX. - fn gen_len(prng: &Prng, len: Self::Len) -> Self; -} - -/// Implemented by types that support being generated in a specific range by a -/// Prng. -pub trait GenRange { - type RangeBound; - - /// Generates a value of the implementing type with the Prng in the - /// specified range. - /// - /// # Panics - /// - /// If the range is empty. - fn gen_range(prng: &Prng, r: impl RangeBounds) -> Self; -} - -/// Implemented by types that support being shuffled by a Prng. -pub trait Shuffle { - /// Shuffles the value with the Prng. - fn shuffle(&mut self, prng: &Prng); -} - -/// Implemented by types that support being shuffled by a Prng. -pub trait ToShuffled { - type Shuffled; - fn to_shuffled(&self, prng: &Prng) -> Self::Shuffled; -} - -impl ToShuffled for T { - type Shuffled = Self; - fn to_shuffled(&self, prng: &Prng) -> Self { - let mut copy = self.clone(); - copy.shuffle(prng); - copy - } -} - -impl Fill for u64 { - fn fill(&mut self, prng: &Prng) { - *self = Self::gen(prng); - } -} - -impl Gen for u64 { - fn gen(prng: &Prng) -> Self { - let env = prng.env(); - debug_assert_in_contract!(env); - internal::Env::prng_u64_in_inclusive_range(env, u64::MIN, u64::MAX).unwrap_infallible() - } -} - -impl GenRange for u64 { - type RangeBound = u64; - - fn gen_range(prng: &Prng, r: impl RangeBounds) -> Self { - let env = prng.env(); - debug_assert_in_contract!(env); - let start_bound = match r.start_bound() { - Bound::Included(b) => *b, - Bound::Excluded(b) => b - .checked_add(1) - .expect_optimized("attempt to add with overflow"), - Bound::Unbounded => u64::MIN, - }; - let end_bound = match r.end_bound() { - Bound::Included(b) => *b, - Bound::Excluded(b) => b - .checked_sub(1) - .expect_optimized("attempt to subtract with overflow"), - Bound::Unbounded => u64::MAX, - }; - internal::Env::prng_u64_in_inclusive_range(env, start_bound, end_bound).unwrap_infallible() - } -} - -impl Fill for Bytes { - /// Fills the Bytes with the Prng. - /// - /// # Panics - /// - /// If the length of Bytes is greater than u32::MAX in length. - fn fill(&mut self, prng: &Prng) { - let env = prng.env(); - debug_assert_in_contract!(env); - let len: u32 = self.len(); - let obj = internal::Env::prng_bytes_new(env, len.into()).unwrap_infallible(); - *self = unsafe { Bytes::unchecked_new(env.clone(), obj) }; - } -} - -impl GenLen for Bytes { - type Len = u32; - /// Generates the Bytes with the Prng of the given length. - fn gen_len(prng: &Prng, len: u32) -> Self { - let env = prng.env(); - debug_assert_in_contract!(env); - let obj = internal::Env::prng_bytes_new(env, len.into()).unwrap_infallible(); - unsafe { Bytes::unchecked_new(env.clone(), obj) } - } -} - -impl Fill for BytesN { - /// Fills the BytesN with the Prng. - /// - /// # Panics - /// - /// If the length of BytesN is greater than u32::MAX in length. - fn fill(&mut self, prng: &Prng) { - let bytesn = Self::gen(prng); - *self = bytesn; - } -} - -impl Gen for BytesN { - /// Generates the BytesN with the Prng. - /// - /// # Panics - /// - /// If the length of BytesN is greater than u32::MAX in length. - fn gen(prng: &Prng) -> Self { - let env = prng.env(); - debug_assert_in_contract!(env); - let len: u32 = N.try_into().unwrap_optimized(); - let obj = internal::Env::prng_bytes_new(env, len.into()).unwrap_infallible(); - unsafe { BytesN::unchecked_new(env.clone(), obj) } - } -} - -impl Fill for [u8] { - /// Fills the slice with the Prng. - /// - /// # Panics - /// - /// If the slice is greater than u32::MAX in length. - fn fill(&mut self, prng: &Prng) { - let env = prng.env(); - debug_assert_in_contract!(env); - let len: u32 = self.len().try_into().unwrap_optimized(); - let bytes: Bytes = internal::Env::prng_bytes_new(env, len.into()) - .unwrap_infallible() - .into_val(env); - bytes.copy_into_slice(self); - } -} - -impl Fill for [u8; N] { - /// Fills the array with the Prng. - /// - /// # Panics - /// - /// If the array is greater than u32::MAX in length. - fn fill(&mut self, prng: &Prng) { - let env = prng.env(); - debug_assert_in_contract!(env); - let len: u32 = N.try_into().unwrap_optimized(); - let bytes: Bytes = internal::Env::prng_bytes_new(env, len.into()) - .unwrap_infallible() - .into_val(env); - bytes.copy_into_slice(self); - } -} - -impl Gen for [u8; N] { - /// Generates the array with the Prng. - /// - /// # Panics - /// - /// If the array is greater than u32::MAX in length. - fn gen(prng: &Prng) -> Self { - let mut v = [0u8; N]; - v.fill(prng); - v - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs b/temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs deleted file mode 100644 index 11b84a2..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/spec_shaking.rs +++ /dev/null @@ -1,433 +0,0 @@ -//! SpecShakingMarker is an internal trait used to ensure that contract type specs -//! are included in the WASM binary when types are used at contract boundaries. -//! -//! The trait is called at three external boundary points: -//! 1. Contract function input parameters -//! 2. Contract function return values -//! 3. Event publishing -//! -//! Types that are only used internally (storage, cross-contract calls) do not -//! need their specs included, so the trait is NOT called from general TryFromVal -//! conversions. -//! -//! The trait has a default no-op implementation. Types generated by contracttype, -//! contractevent, and contracterror macros implement this trait to include their -//! spec XDR in the WASM's contractspecv0 section. -//! -//! Types whose layout includes their inner types inline (`Option`, -//! `Result`, tuples) call `T::spec_shaking_marker()` directly for -//! each inner type. -//! -//! Types whose size is independent of their inner types (`Vec`, -//! `Map`, `&T`, `&mut T`) use [`keep_reachable`] to reference each -//! inner type's marker without calling it. Recursive definitions are -//! possible through these types, so a direct call would risk a runtime cycle. - -/// Trait for types that may include their spec in the WASM binary. -/// -/// This trait is used internally by the SDK to ensure contract type specs -/// are included when types are used at external boundaries (function params, -/// return values, events). -/// -/// Types with `#[contracttype]`, `#[contractevent]`, or `#[contracterror]` -/// will have implementations that include their spec. All other types have -/// a no-op implementation. -#[doc(hidden)] -pub trait SpecShakingMarker { - /// Include this type's spec in the WASM binary. - /// - /// For primitive types and built-in SDK types, this is a no-op. - /// For user-defined contract types, this ensures the spec XDR is - /// included in the contractspecv0 section. - #[inline(always)] - fn spec_shaking_marker() {} -} - -/// Keeps `f`'s symbol alive through the linker's dead-code-elimination -/// pass without invoking `f` at runtime. Takes `f` as a function pointer -/// and volatile-reads it. The same technique is used to keep the `MARKER` -/// byte statics alive (see `soroban-sdk-macros/src/shaking.rs`). -#[doc(hidden)] -#[inline(always)] -fn keep_reachable(_f: fn()) { - #[cfg(target_family = "wasm")] - let _ = unsafe { core::ptr::read_volatile(&_f) }; -} - -// Primitive type implementations (no-op) -impl SpecShakingMarker for () {} -impl SpecShakingMarker for bool {} -impl SpecShakingMarker for u32 {} -impl SpecShakingMarker for i32 {} -impl SpecShakingMarker for u64 {} -impl SpecShakingMarker for i64 {} -impl SpecShakingMarker for u128 {} -impl SpecShakingMarker for i128 {} - -// Reference implementations — use `keep_reachable` because &T is -// pointer-sized independent of T, so recursive definitions through -// references could be possible. Currently, limitations of generics -// within `map_type` prevent this from working, so this is done -// out of caution. -impl SpecShakingMarker for &T { - #[inline(always)] - fn spec_shaking_marker() { - keep_reachable(T::spec_shaking_marker); - } -} - -impl SpecShakingMarker for &mut T { - #[inline(always)] - fn spec_shaking_marker() { - keep_reachable(T::spec_shaking_marker); - } -} - -// Option implementation - includes inner type's spec -impl SpecShakingMarker for Option { - #[inline(always)] - fn spec_shaking_marker() { - T::spec_shaking_marker(); - } -} - -// Result implementation - includes both types' specs -impl SpecShakingMarker for Result { - #[inline(always)] - fn spec_shaking_marker() { - T::spec_shaking_marker(); - E::spec_shaking_marker(); - } -} - -// Tuple implementations -impl SpecShakingMarker for (T0,) { - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - } -} - -impl SpecShakingMarker for (T0, T1) { - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - } -} - -impl SpecShakingMarker - for (T0, T1, T2) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - T7: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - T7::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - T7: SpecShakingMarker, - T8: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - T7::spec_shaking_marker(); - T8::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - T7: SpecShakingMarker, - T8: SpecShakingMarker, - T9: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - T7::spec_shaking_marker(); - T8::spec_shaking_marker(); - T9::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - T7: SpecShakingMarker, - T8: SpecShakingMarker, - T9: SpecShakingMarker, - T10: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - T7::spec_shaking_marker(); - T8::spec_shaking_marker(); - T9::spec_shaking_marker(); - T10::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - T7: SpecShakingMarker, - T8: SpecShakingMarker, - T9: SpecShakingMarker, - T10: SpecShakingMarker, - T11: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - T7::spec_shaking_marker(); - T8::spec_shaking_marker(); - T9::spec_shaking_marker(); - T10::spec_shaking_marker(); - T11::spec_shaking_marker(); - } -} - -impl< - T0: SpecShakingMarker, - T1: SpecShakingMarker, - T2: SpecShakingMarker, - T3: SpecShakingMarker, - T4: SpecShakingMarker, - T5: SpecShakingMarker, - T6: SpecShakingMarker, - T7: SpecShakingMarker, - T8: SpecShakingMarker, - T9: SpecShakingMarker, - T10: SpecShakingMarker, - T11: SpecShakingMarker, - T12: SpecShakingMarker, - > SpecShakingMarker for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) -{ - #[inline(always)] - fn spec_shaking_marker() { - T0::spec_shaking_marker(); - T1::spec_shaking_marker(); - T2::spec_shaking_marker(); - T3::spec_shaking_marker(); - T4::spec_shaking_marker(); - T5::spec_shaking_marker(); - T6::spec_shaking_marker(); - T7::spec_shaking_marker(); - T8::spec_shaking_marker(); - T9::spec_shaking_marker(); - T10::spec_shaking_marker(); - T11::spec_shaking_marker(); - T12::spec_shaking_marker(); - } -} - -// SDK type implementations (no-op for built-in types, propagate for containers) -// These are imported via crate:: to avoid circular dependencies - -impl SpecShakingMarker for crate::Address {} -impl SpecShakingMarker for crate::Bytes {} -impl SpecShakingMarker for crate::BytesN {} -impl SpecShakingMarker for crate::String {} -impl SpecShakingMarker for crate::Symbol {} -impl SpecShakingMarker for crate::U256 {} -impl SpecShakingMarker for crate::I256 {} -impl SpecShakingMarker for crate::Timepoint {} -impl SpecShakingMarker for crate::Duration {} -impl SpecShakingMarker for crate::Val {} -impl SpecShakingMarker for crate::Error {} - -// SDK Container types - Vec and Map use `keep_reachable` to allow for recursive definitions. -impl SpecShakingMarker for crate::Vec { - #[inline(always)] - fn spec_shaking_marker() { - keep_reachable(T::spec_shaking_marker); - } -} - -impl SpecShakingMarker for crate::Map { - #[inline(always)] - fn spec_shaking_marker() { - keep_reachable(K::spec_shaking_marker); - keep_reachable(V::spec_shaking_marker); - } -} - -// Additional SDK types -impl SpecShakingMarker for crate::MuxedAddress {} -impl SpecShakingMarker for crate::crypto::Hash {} -impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381G1Affine {} -impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381G2Affine {} -impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381Fp {} -impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381Fp2 {} -impl SpecShakingMarker for crate::crypto::bls12_381::Bls12381Fr {} -impl SpecShakingMarker for crate::crypto::bn254::Bn254G1Affine {} -impl SpecShakingMarker for crate::crypto::bn254::Bn254G2Affine {} -impl SpecShakingMarker for crate::crypto::bn254::Bn254Fp {} -impl SpecShakingMarker for crate::crypto::bn254::Bn254Fr {} - -// Auth types - these have export=false but are legitimately used at external -// boundaries (as inputs to __check_auth in custom account contracts). -// They don't emit specs themselves because they're internal SDK types. -impl SpecShakingMarker for crate::auth::Context {} -impl SpecShakingMarker for crate::auth::ContractContext {} -impl SpecShakingMarker for crate::auth::CreateContractHostFnContext {} -impl SpecShakingMarker for crate::auth::CreateContractWithConstructorHostFnContext {} -impl SpecShakingMarker for crate::auth::ContractExecutable {} -impl SpecShakingMarker for crate::auth::InvokerContractAuthEntry {} -impl SpecShakingMarker for crate::auth::SubContractInvocation {} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/storage.rs b/temp_sdk/soroban-sdk-26.0.1/src/storage.rs deleted file mode 100644 index c2a2c11..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/storage.rs +++ /dev/null @@ -1,775 +0,0 @@ -//! Storage contains types for storing data for the currently executing contract. -use core::fmt::Debug; - -use crate::{ - env::internal::{self, ContractTtlExtension, StorageType, Val}, - unwrap::{UnwrapInfallible, UnwrapOptimized}, - Env, IntoVal, TryFromVal, -}; - -/// Storage stores and retrieves data for the currently executing contract. -/// -/// All data stored can only be queried and modified by the contract that stores -/// it. Contracts cannot query or modify data stored by other contracts. -/// -/// There are three types of storage - Temporary, Persistent, and Instance. -/// -/// Temporary entries are the cheaper storage option and are never in the Expired State Stack (ESS). Whenever -/// a TemporaryEntry expires, the entry is permanently deleted and cannot be recovered. -/// This storage type is best for entries that are only relevant for short periods of -/// time or for entries that can be arbitrarily recreated. -/// -/// Persistent entries are the more expensive storage type. Whenever -/// a persistent entry expires, it is deleted from the ledger, sent to the ESS -/// and can be recovered via an operation in Stellar Core. Only a single version of a -/// persistent entry can exist at a time. -/// -/// Instance storage is used to store entries within the Persistent contract -/// instance entry, allowing users to tie that data directly to the TTL -/// of the instance. Instance storage is good for global contract data like -/// metadata, admin accounts, or pool reserves. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{Env, Symbol}; -/// -/// # use soroban_sdk::{contract, contractimpl, symbol_short, BytesN}; -/// # -/// # #[contract] -/// # pub struct Contract; -/// # -/// # #[contractimpl] -/// # impl Contract { -/// # pub fn f(env: Env) { -/// let storage = env.storage(); -/// let key = symbol_short!("key"); -/// storage.persistent().set(&key, &1); -/// assert_eq!(storage.persistent().has(&key), true); -/// assert_eq!(storage.persistent().get::<_, i32>(&key), Some(1)); -/// # } -/// # } -/// # -/// # #[cfg(feature = "testutils")] -/// # fn main() { -/// # let env = Env::default(); -/// # let contract_id = env.register(Contract, ()); -/// # ContractClient::new(&env, &contract_id).f(); -/// # } -/// # #[cfg(not(feature = "testutils"))] -/// # fn main() { } -/// ``` -#[derive(Clone)] -pub struct Storage { - env: Env, -} - -impl Debug for Storage { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Storage") - } -} - -impl Storage { - #[inline(always)] - pub(crate) fn new(env: &Env) -> Storage { - Storage { env: env.clone() } - } - - /// Storage for data that can stay in the ledger forever until deleted. - /// - /// Persistent entries might expire and be removed from the ledger if they run out - /// of the rent balance. However, expired entries can be restored and - /// they cannot be recreated. This means these entries - /// behave 'as if' they were stored in the ledger forever. - /// - /// This should be used for data that requires persistency, such as token - /// balances, user properties etc. - pub fn persistent(&self) -> Persistent { - debug_assert_in_contract!(self.env); - - Persistent { - storage: self.clone(), - } - } - - /// Storage for data that may stay in ledger only for a limited amount of - /// time. - /// - /// Temporary storage is cheaper than Persistent storage. - /// - /// Temporary entries will be removed from the ledger after their lifetime - /// ends. Removed entries can be created again, potentially with different - /// values. - /// - /// This should be used for data that needs to only exist for a limited - /// period of time, such as oracle data, claimable balances, offer, etc. - pub fn temporary(&self) -> Temporary { - debug_assert_in_contract!(self.env); - - Temporary { - storage: self.clone(), - } - } - - /// Storage for a **small amount** of persistent data associated with - /// the current contract's instance. - /// - /// Storing a small amount of frequently used data in instance storage is - /// likely cheaper than storing it separately in Persistent storage. - /// - /// Instance storage is tightly coupled with the contract instance: it will - /// be loaded from the ledger every time the contract instance itself is - /// loaded. It also won't appear in the ledger footprint. *All* - /// the data stored in the instance storage is read from ledger every time - /// the contract is used and it doesn't matter whether contract uses the - /// storage or not. - /// - /// This has the same lifetime properties as Persistent storage, i.e. - /// the data semantically stays in the ledger forever and can be - /// expired/restored. - /// - /// The amount of data that can be stored in the instance storage is limited - /// by the ledger entry size (a network-defined parameter). It is - /// in the order of 100 KB serialized. - /// - /// This should be used for small data directly associated with the current - /// contract, such as its admin, configuration settings, tokens the contract - /// operates on etc. Do not use this with any data that can scale in - /// unbounded fashion (such as user balances). - pub fn instance(&self) -> Instance { - debug_assert_in_contract!(self.env); - - Instance { - storage: self.clone(), - } - } - - /// Returns the maximum time-to-live (TTL) for all the Soroban ledger entries. - /// - /// TTL is the number of ledgers left until the instance entry is considered - /// expired, excluding the current ledger. Maximum TTL represents the maximum - /// possible TTL of an entry and maximum extension via `extend_ttl` methods. - pub fn max_ttl(&self) -> u32 { - let seq = self.env.ledger().sequence(); - let max = self.env.ledger().max_live_until_ledger(); - max.saturating_sub(seq) - } - - /// Returns if there is a value stored for the given key in the currently - /// executing contracts storage. - #[inline(always)] - pub(crate) fn has(&self, key: &K, storage_type: StorageType) -> bool - where - K: IntoVal, - { - self.has_internal(key.into_val(&self.env), storage_type) - } - - /// Returns the value stored for the given key in the currently executing - /// contract's storage, when present. - /// - /// Returns `None` when the value is missing. - /// - /// If the value is present, then the returned value will be a result of - /// converting the internal value representation to `V`, or will panic if - /// the conversion to `V` fails. - #[inline(always)] - pub(crate) fn get(&self, key: &K, storage_type: StorageType) -> Option - where - K: IntoVal, - V: TryFromVal, - { - let key = key.into_val(&self.env); - if self.has_internal(key, storage_type) { - let rv = self.get_internal(key, storage_type); - Some(V::try_from_val(&self.env, &rv).unwrap_optimized()) - } else { - None - } - } - - /// Returns the value there is a value stored for the given key in the - /// currently executing contract's storage. - /// - /// The returned value is a result of converting the internal value - pub(crate) fn set(&self, key: &K, val: &V, storage_type: StorageType) - where - K: IntoVal, - V: IntoVal, - { - let env = &self.env; - internal::Env::put_contract_data(env, key.into_val(env), val.into_val(env), storage_type) - .unwrap_infallible(); - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. - /// - /// The returned value is the value stored after updating. - pub(crate) fn update( - &self, - key: &K, - storage_type: StorageType, - f: impl FnOnce(Option) -> V, - ) -> V - where - K: IntoVal, - V: TryFromVal, - V: IntoVal, - { - let key = key.into_val(&self.env); - let val = self.get(&key, storage_type); - let val = f(val); - self.set(&key, &val, storage_type); - val - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. If the function returns an error it - /// will be passed through. - /// - /// The returned value is the value stored after updating. - pub(crate) fn try_update( - &self, - key: &K, - storage_type: StorageType, - f: impl FnOnce(Option) -> Result, - ) -> Result - where - K: IntoVal, - V: TryFromVal, - V: IntoVal, - { - let key = key.into_val(&self.env); - let val = self.get(&key, storage_type); - let val = f(val)?; - self.set(&key, &val, storage_type); - Ok(val) - } - - pub(crate) fn extend_ttl( - &self, - key: &K, - storage_type: StorageType, - threshold: u32, - extend_to: u32, - ) where - K: IntoVal, - { - let env = &self.env; - internal::Env::extend_contract_data_ttl( - env, - key.into_val(env), - storage_type, - threshold.into(), - extend_to.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the data with limits on the extension. - /// - /// Extends the TTL of the data to be up to `extend_to` ledgers. The extension - /// only happens if it exceeds `min_extension` ledgers, otherwise this is a no-op. - /// The amount of extension will not exceed `max_extension` ledgers. - /// - /// The TTL is the number of ledgers between the current ledger and the final - /// ledger the data can still be accessed. - pub(crate) fn extend_ttl_with_limits( - &self, - key: &K, - storage_type: StorageType, - extend_to: u32, - min_extension: u32, - max_extension: u32, - ) where - K: IntoVal, - { - let env = &self.env; - internal::Env::extend_contract_data_ttl_v2( - env, - key.into_val(env), - storage_type, - extend_to.into(), - min_extension.into(), - max_extension.into(), - ) - .unwrap_infallible(); - } - - /// Removes the key and the corresponding value from the currently executing - /// contract's storage. - /// - /// No-op if the key does not exist. - #[inline(always)] - pub(crate) fn remove(&self, key: &K, storage_type: StorageType) - where - K: IntoVal, - { - let env = &self.env; - internal::Env::del_contract_data(env, key.into_val(env), storage_type).unwrap_infallible(); - } - - fn has_internal(&self, key: Val, storage_type: StorageType) -> bool { - internal::Env::has_contract_data(&self.env, key, storage_type) - .unwrap_infallible() - .into() - } - - fn get_internal(&self, key: Val, storage_type: StorageType) -> Val { - internal::Env::get_contract_data(&self.env, key, storage_type).unwrap_infallible() - } -} - -pub struct Persistent { - storage: Storage, -} - -impl Persistent { - pub fn has(&self, key: &K) -> bool - where - K: IntoVal, - { - self.storage.has(key, StorageType::Persistent) - } - - pub fn get(&self, key: &K) -> Option - where - V::Error: Debug, - K: IntoVal, - V: TryFromVal, - { - self.storage.get(key, StorageType::Persistent) - } - - pub fn set(&self, key: &K, val: &V) - where - K: IntoVal, - V: IntoVal, - { - self.storage.set(key, val, StorageType::Persistent) - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. - /// - /// The returned value is the value stored after updating. - pub fn update(&self, key: &K, f: impl FnOnce(Option) -> V) -> V - where - K: IntoVal, - V: IntoVal, - V: TryFromVal, - { - self.storage.update(key, StorageType::Persistent, f) - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. If the function returns an error it - /// will be passed through. - /// - /// The returned value is the value stored after updating. - pub fn try_update( - &self, - key: &K, - f: impl FnOnce(Option) -> Result, - ) -> Result - where - K: IntoVal, - V: IntoVal, - V: TryFromVal, - { - self.storage.try_update(key, StorageType::Persistent, f) - } - - /// Extend the TTL of the data under the key. - /// - /// Extends the TTL only if the TTL for the provided data is below `threshold` ledgers. - /// The TTL will then become `extend_to`. - /// - /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. - pub fn extend_ttl(&self, key: &K, threshold: u32, extend_to: u32) - where - K: IntoVal, - { - self.storage - .extend_ttl(key, StorageType::Persistent, threshold, extend_to) - } - - /// Extend the TTL of the data under the key with limits on the extension. - /// - /// Extends the TTL of the data to be up to `extend_to` ledgers. The extension - /// only happens if it exceeds `min_extension` ledgers, otherwise this is a no-op. - /// The amount of extension will not exceed `max_extension` ledgers. - /// - /// The TTL is the number of ledgers between the current ledger and the final - /// ledger the data can still be accessed. - pub fn extend_ttl_with_limits( - &self, - key: &K, - extend_to: u32, - min_extension: u32, - max_extension: u32, - ) where - K: IntoVal, - { - self.storage.extend_ttl_with_limits( - key, - StorageType::Persistent, - extend_to, - min_extension, - max_extension, - ) - } - - #[inline(always)] - pub fn remove(&self, key: &K) - where - K: IntoVal, - { - self.storage.remove(key, StorageType::Persistent) - } -} - -pub struct Temporary { - storage: Storage, -} - -impl Temporary { - pub fn has(&self, key: &K) -> bool - where - K: IntoVal, - { - self.storage.has(key, StorageType::Temporary) - } - - pub fn get(&self, key: &K) -> Option - where - V::Error: Debug, - K: IntoVal, - V: TryFromVal, - { - self.storage.get(key, StorageType::Temporary) - } - - pub fn set(&self, key: &K, val: &V) - where - K: IntoVal, - V: IntoVal, - { - self.storage.set(key, val, StorageType::Temporary) - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. - /// - /// The returned value is the value stored after updating. - pub fn update(&self, key: &K, f: impl FnOnce(Option) -> V) -> V - where - K: IntoVal, - V: IntoVal, - V: TryFromVal, - { - self.storage.update(key, StorageType::Temporary, f) - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. If the function returns an error it - /// will be passed through. - /// - /// The returned value is the value stored after updating. - pub fn try_update( - &self, - key: &K, - f: impl FnOnce(Option) -> Result, - ) -> Result - where - K: IntoVal, - V: IntoVal, - V: TryFromVal, - { - self.storage.try_update(key, StorageType::Temporary, f) - } - - /// Extend the TTL of the data under the key. - /// - /// Extends the TTL only if the TTL for the provided data is below `threshold` ledgers. - /// The TTL will then become `extend_to`. - /// - /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. - pub fn extend_ttl(&self, key: &K, threshold: u32, extend_to: u32) - where - K: IntoVal, - { - self.storage - .extend_ttl(key, StorageType::Temporary, threshold, extend_to) - } - - #[inline(always)] - pub fn remove(&self, key: &K) - where - K: IntoVal, - { - self.storage.remove(key, StorageType::Temporary) - } -} - -pub struct Instance { - storage: Storage, -} - -impl Instance { - pub fn has(&self, key: &K) -> bool - where - K: IntoVal, - { - self.storage.has(key, StorageType::Instance) - } - - pub fn get(&self, key: &K) -> Option - where - V::Error: Debug, - K: IntoVal, - V: TryFromVal, - { - self.storage.get(key, StorageType::Instance) - } - - pub fn set(&self, key: &K, val: &V) - where - K: IntoVal, - V: IntoVal, - { - self.storage.set(key, val, StorageType::Instance) - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. - /// - /// The returned value is the value stored after updating. - pub fn update(&self, key: &K, f: impl FnOnce(Option) -> V) -> V - where - K: IntoVal, - V: IntoVal, - V: TryFromVal, - { - self.storage.update(key, StorageType::Instance, f) - } - - /// Update a value stored against a key. - /// - /// Loads the value, calls the function with it, then sets the value to the - /// returned value of the function. If no value is stored with the key then - /// the function is called with None. If the function returns an error it - /// will be passed through. - /// - /// The returned value is the value stored after updating. - pub fn try_update( - &self, - key: &K, - f: impl FnOnce(Option) -> Result, - ) -> Result - where - K: IntoVal, - V: IntoVal, - V: TryFromVal, - { - self.storage.try_update(key, StorageType::Instance, f) - } - - #[inline(always)] - pub fn remove(&self, key: &K) - where - K: IntoVal, - { - self.storage.remove(key, StorageType::Instance) - } - - /// Extend the TTL of the contract instance and code. - /// - /// Extends the TTL of the instance and code only if the TTL for the provided contract is below `threshold` ledgers. - /// The TTL will then become `extend_to`. Note that the `threshold` check and TTL extensions are done for both the - /// contract code and contract instance, so it's possible that one is bumped but not the other depending on what the - /// current TTL's are. - /// - /// The TTL is the number of ledgers between the current ledger and the final ledger the data can still be accessed. - pub fn extend_ttl(&self, threshold: u32, extend_to: u32) { - internal::Env::extend_current_contract_instance_and_code_ttl( - &self.storage.env, - threshold.into(), - extend_to.into(), - ) - .unwrap_infallible(); - } - - /// Extend the TTL of the contract instance and code with limits on the extension. - /// - /// Extends the TTL of the instance and code to be up to `extend_to` ledgers. - /// The extension only happens if it exceeds `min_extension` ledgers, otherwise - /// this is a no-op. The amount of extension will not exceed `max_extension` ledgers. - /// - /// Note that the extension is applied to both the contract code and contract instance, - /// so it's possible that one is extended but not the other depending on their current TTLs. - /// - /// The TTL is the number of ledgers between the current ledger and the final ledger - /// the data can still be accessed. - pub fn extend_ttl_with_limits(&self, extend_to: u32, min_extension: u32, max_extension: u32) { - internal::Env::extend_contract_instance_and_code_ttl_v2( - &self.storage.env, - self.storage.env.current_contract_address().to_object(), - ContractTtlExtension::InstanceAndCode, - extend_to.into(), - min_extension.into(), - max_extension.into(), - ) - .unwrap_infallible(); - } -} - -#[cfg(any(test, feature = "testutils"))] -#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] -mod testutils { - use super::*; - use crate::{testutils, xdr, Map, TryIntoVal}; - - impl testutils::storage::Instance for Instance { - fn all(&self) -> Map { - let env = &self.storage.env; - let storage = env.host().get_stored_entries().unwrap(); - let address: xdr::ScAddress = env.current_contract_address().try_into().unwrap(); - for entry in storage { - let (k, Some((v, _))) = entry else { - continue; - }; - let xdr::LedgerKey::ContractData(xdr::LedgerKeyContractData { - ref contract, .. - }) = *k - else { - continue; - }; - if contract != &address { - continue; - } - let xdr::LedgerEntry { - data: - xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry { - key: xdr::ScVal::LedgerKeyContractInstance, - val: - xdr::ScVal::ContractInstance(xdr::ScContractInstance { - ref storage, - .. - }), - .. - }), - .. - } = *v - else { - continue; - }; - return match storage { - Some(map) => { - let map: Val = - Val::try_from_val(env, &xdr::ScVal::Map(Some(map.clone()))).unwrap(); - map.try_into_val(env).unwrap() - } - None => Map::new(env), - }; - } - panic!("contract instance for current contract address not found"); - } - - fn get_ttl(&self) -> u32 { - let env = &self.storage.env; - env.host() - .get_contract_instance_live_until_ledger(env.current_contract_address().to_object()) - .unwrap() - .checked_sub(env.ledger().sequence()) - .unwrap() - } - } - - impl testutils::storage::Persistent for Persistent { - fn all(&self) -> Map { - all(&self.storage.env, xdr::ContractDataDurability::Persistent) - } - - fn get_ttl>(&self, key: &K) -> u32 { - let env = &self.storage.env; - env.host() - .get_contract_data_live_until_ledger(key.into_val(env), StorageType::Persistent) - .unwrap() - .checked_sub(env.ledger().sequence()) - .unwrap() - } - } - - impl testutils::storage::Temporary for Temporary { - fn all(&self) -> Map { - all(&self.storage.env, xdr::ContractDataDurability::Temporary) - } - - fn get_ttl>(&self, key: &K) -> u32 { - let env = &self.storage.env; - env.host() - .get_contract_data_live_until_ledger(key.into_val(env), StorageType::Temporary) - .unwrap() - .checked_sub(env.ledger().sequence()) - .unwrap() - } - } - - fn all(env: &Env, d: xdr::ContractDataDurability) -> Map { - let storage = env.host().get_stored_entries().unwrap(); - let mut map = Map::::new(env); - for entry in storage { - let (_, Some((v, _))) = entry else { - continue; - }; - let xdr::LedgerEntry { - data: - xdr::LedgerEntryData::ContractData(xdr::ContractDataEntry { - ref key, - ref val, - durability, - .. - }), - .. - } = *v - else { - continue; - }; - if d != durability { - continue; - } - let Ok(key) = Val::try_from_val(env, key) else { - continue; - }; - let Ok(val) = Val::try_from_val(env, val) else { - continue; - }; - map.set(key, val); - } - map - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/string.rs b/temp_sdk/soroban-sdk-26.0.1/src/string.rs deleted file mode 100644 index e4382a6..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/string.rs +++ /dev/null @@ -1,417 +0,0 @@ -use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; - -use super::{ - env::internal::{Env as _, EnvBase as _, StringObject}, - Bytes, ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, -}; - -use crate::unwrap::{UnwrapInfallible, UnwrapOptimized}; -#[cfg(doc)] -use crate::{storage::Storage, Map, Vec}; - -#[cfg(not(target_family = "wasm"))] -use super::xdr::{ScString, ScVal}; - -/// String is a contiguous growable array type containing `u8`s. -/// -/// The array is stored in the Host and available to the Guest through the -/// functions defined on String. -/// -/// String values can be stored as [Storage], or in other types like [Vec], -/// [Map], etc. -/// -/// ### Examples -/// -/// String values can be created from slices: -/// ``` -/// use soroban_sdk::{String, Env}; -/// -/// let env = Env::default(); -/// let msg = "a message"; -/// let s = String::from_str(&env, msg); -/// let mut out = [0u8; 9]; -/// s.copy_into_slice(&mut out); -/// assert_eq!(msg.as_bytes(), out) -/// ``` -#[derive(Clone)] -pub struct String { - env: Env, - obj: StringObject, -} - -impl Debug for String { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - #[cfg(target_family = "wasm")] - write!(f, "String(..)")?; - #[cfg(not(target_family = "wasm"))] - write!(f, "String({self})")?; - Ok(()) - } -} - -impl Eq for String {} - -impl PartialEq for String { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for String { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for String { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - #[cfg(not(target_family = "wasm"))] - if !self.env.is_same_env(&other.env) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = self - .env - .obj_cmp(self.obj.to_val(), other.obj.to_val()) - .unwrap_infallible(); - v.cmp(&0) - } -} - -impl TryFromVal for String { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &String) -> Result { - Ok(v.clone()) - } -} - -impl TryFromVal for String { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &StringObject) -> Result { - Ok(unsafe { String::unchecked_new(env.clone(), *val) }) - } -} - -impl TryFromVal for String { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(StringObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &String) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&String) -> Result { - Ok(v.to_val()) - } -} - -impl From for Val { - #[inline(always)] - fn from(v: String) -> Self { - v.obj.into() - } -} - -impl From for StringObject { - #[inline(always)] - fn from(v: String) -> Self { - v.obj - } -} - -impl From<&String> for StringObject { - #[inline(always)] - fn from(v: &String) -> Self { - v.obj - } -} - -impl From<&String> for String { - #[inline(always)] - fn from(v: &String) -> Self { - v.clone() - } -} - -impl From<&String> for Bytes { - fn from(v: &String) -> Self { - Env::string_to_bytes(&v.env, v.obj.clone()) - .unwrap_infallible() - .into_val(&v.env) - } -} - -impl From for Bytes { - fn from(v: String) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&String> for ScVal { - fn from(v: &String) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for ScVal { - fn from(v: String) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for String { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok( - StringObject::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible(), - ) - } -} - -impl TryFromVal for String { - type Error = ConversionError; - - fn try_from_val(env: &Env, v: &&str) -> Result { - Ok(String::from_str(env, v)) - } -} - -#[cfg(not(target_family = "wasm"))] -impl core::fmt::Display for String { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - let sc_val: ScVal = self.try_into().unwrap(); - if let ScVal::String(ScString(s)) = sc_val { - let utf8_s = s.to_utf8_string().unwrap(); - write!(f, "{utf8_s}")?; - } else { - panic!("value is not a string"); - } - Ok(()) - } -} - -impl String { - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: StringObject) -> Self { - Self { env, obj } - } - - #[inline(always)] - pub fn env(&self) -> &Env { - &self.env - } - - pub fn as_val(&self) -> &Val { - self.obj.as_val() - } - - pub fn to_val(&self) -> Val { - self.obj.to_val() - } - - pub fn as_object(&self) -> &StringObject { - &self.obj - } - - pub fn to_object(&self) -> StringObject { - self.obj - } - - #[inline(always)] - #[doc(hidden)] - #[deprecated(note = "use from_str")] - pub fn from_slice(env: &Env, slice: &str) -> String { - Self::from_str(env, slice) - } - - #[inline(always)] - pub fn from_bytes(env: &Env, b: &[u8]) -> String { - String { - env: env.clone(), - obj: env.string_new_from_slice(b).unwrap_optimized(), - } - } - - #[inline(always)] - pub fn from_str(env: &Env, s: &str) -> String { - String { - env: env.clone(), - obj: env.string_new_from_slice(s.as_bytes()).unwrap_optimized(), - } - } - - #[inline(always)] - pub fn len(&self) -> u32 { - self.env().string_len(self.obj).unwrap_infallible().into() - } - - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Copy the bytes in [String] into the given slice. - /// - /// ### Panics - /// - /// If the output slice and string are of different lengths. - #[inline(always)] - pub fn copy_into_slice(&self, slice: &mut [u8]) { - let env = self.env(); - if self.len() as usize != slice.len() { - sdk_panic!("String::copy_into_slice with mismatched slice length") - } - env.string_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) - .unwrap_optimized(); - } - - /// Converts the contents of the String into a respective Bytes object. - pub fn to_bytes(&self) -> Bytes { - self.into() - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::IntoVal; - - #[test] - fn string_from_and_to_slices() { - let env = Env::default(); - - let msg = "a message"; - let s = String::from_str(&env, msg); - let mut out = [0u8; 9]; - s.copy_into_slice(&mut out); - assert_eq!(msg.as_bytes(), out) - } - - #[test] - fn string_from_and_to_bytes() { - let env = Env::default(); - - let msg = b"a message"; - let s = String::from_bytes(&env, msg); - let mut out = [0u8; 9]; - s.copy_into_slice(&mut out); - assert_eq!(msg, &out) - } - - #[test] - #[should_panic] - fn string_to_short_slice() { - let env = Env::default(); - let msg = "a message"; - let s = String::from_str(&env, msg); - let mut out = [0u8; 8]; - s.copy_into_slice(&mut out); - } - - #[test] - #[should_panic] - fn string_to_long_slice() { - let env = Env::default(); - let msg = "a message"; - let s = String::from_str(&env, msg); - let mut out = [0u8; 10]; - s.copy_into_slice(&mut out); - } - - #[test] - fn string_to_val() { - let env = Env::default(); - - let s = String::from_str(&env, "abcdef"); - let val: Val = s.clone().into_val(&env); - let rt: String = val.into_val(&env); - - assert_eq!(s, rt); - } - - #[test] - fn ref_string_to_val() { - let env = Env::default(); - - let s = String::from_str(&env, "abcdef"); - let val: Val = (&s).into_val(&env); - let rt: String = val.into_val(&env); - - assert_eq!(s, rt); - } - - #[test] - fn double_ref_string_to_val() { - let env = Env::default(); - - let s = String::from_str(&env, "abcdef"); - let val: Val = (&&s).into_val(&env); - let rt: String = val.into_val(&env); - - assert_eq!(s, rt); - } - - #[test] - fn test_string_to_bytes() { - let env = Env::default(); - let s = String::from_str(&env, "abcdef"); - let b: Bytes = s.clone().into(); - assert_eq!(b.len(), 6); - let mut slice = [0u8; 6]; - b.copy_into_slice(&mut slice); - assert_eq!(&slice, b"abcdef"); - let b2 = s.to_bytes(); - assert_eq!(b, b2); - } - - #[test] - fn test_string_accepts_any_bytes_even_invalid_utf8() { - let env = Env::default(); - let input = b"a\xc3\x28d"; // \xc3 is invalid utf8 - let s = String::from_bytes(&env, &input[..]); - let b = s.to_bytes().to_buffer::<4>(); - assert_eq!(b.as_slice(), input); - } - - #[test] - fn test_string_display_to_string() { - let env = Env::default(); - let input = "abcdef"; - let s = String::from_str(&env, input); - let rt = s.to_string(); - assert_eq!(input, &rt); - } - - #[test] - #[should_panic = "Utf8Error"] - fn test_string_display_to_string_invalid_utf8() { - let env = Env::default(); - let input = b"a\xc3\x28d"; // \xc3 is invalid utf8 - let s = String::from_bytes(&env, &input[..]); - let _ = s.to_string(); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/symbol.rs b/temp_sdk/soroban-sdk-26.0.1/src/symbol.rs deleted file mode 100644 index 2dfbb34..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/symbol.rs +++ /dev/null @@ -1,299 +0,0 @@ -use core::{cmp::Ordering, convert::Infallible, fmt::Debug}; - -use super::{ - env::internal::{Env as _, Symbol as SymbolVal, SymbolSmall}, - ConversionError, Env, TryFromVal, TryIntoVal, Val, -}; - -#[cfg(not(target_family = "wasm"))] -use super::env::SymbolStr; - -#[cfg(not(target_family = "wasm"))] -use crate::env::internal::xdr::{ScSymbol, ScVal}; -use crate::{ - env::MaybeEnv, - unwrap::{UnwrapInfallible, UnwrapOptimized}, -}; - -/// Symbol is a short string with a limited character set. -/// -/// Valid characters are `a-zA-Z0-9_` and maximum length is 32 characters. -/// -/// Symbols are used for the for symbolic identifiers, such as function -/// names and user-defined structure field/enum variant names. That's why -/// these idenfiers have limited length. -/// -/// While Symbols up to 32 characters long are allowed, Symbols that are 9 -/// characters long or shorter are more efficient at runtime and also can be -/// computed at compile time. -#[derive(Clone)] -pub struct Symbol { - env: MaybeEnv, - val: SymbolVal, -} - -impl Debug for Symbol { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - #[cfg(target_family = "wasm")] - write!(f, "Symbol(..)")?; - #[cfg(not(target_family = "wasm"))] - write!(f, "Symbol({})", self.to_string())?; - Ok(()) - } -} - -impl Eq for Symbol {} - -impl PartialEq for Symbol { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for Symbol { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Symbol { - fn cmp(&self, other: &Self) -> Ordering { - let self_raw = self.val.to_val(); - let other_raw = other.val.to_val(); - - match ( - SymbolSmall::try_from(self_raw), - SymbolSmall::try_from(other_raw), - ) { - // Compare small symbols. - (Ok(self_sym), Ok(other_sym)) => self_sym.cmp(&other_sym), - // The object-to-small symbol comparisons are handled by `obj_cmp`, - // so it's safe to handle all the other cases using it. - _ => { - let (e1, e2): (Result, Result) = - (self.env.clone().try_into(), other.env.clone().try_into()); - match (e1, e2) { - (Err(_), Err(_)) => { - panic!("symbol object is missing the env reference"); - } - (Err(_), Ok(e)) | (Ok(e), Err(_)) => { - let v = e.obj_cmp(self_raw, other_raw).unwrap_infallible(); - v.cmp(&0) - } - #[cfg(not(target_family = "wasm"))] - (Ok(e1), Ok(e2)) => { - if !e1.is_same_env(&e2) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = e1.obj_cmp(self_raw, other_raw).unwrap_infallible(); - v.cmp(&0) - } - #[cfg(target_family = "wasm")] - (Ok(e), Ok(_)) => { - let v = e.obj_cmp(self_raw, other_raw).unwrap_infallible(); - v.cmp(&0) - } - } - } - } - } -} - -impl TryFromVal for Symbol { - type Error = Infallible; - - fn try_from_val(env: &Env, val: &SymbolVal) -> Result { - Ok(unsafe { Symbol::unchecked_new(env.clone(), *val) }) - } -} - -impl TryFromVal for Symbol { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(SymbolVal::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &Symbol) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&Symbol) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal for Symbol { - type Error = ConversionError; - - fn try_from_val(env: &Env, val: &&str) -> Result { - Ok(SymbolVal::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Symbol> for ScVal { - fn from(v: &Symbol) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - if let Ok(ss) = SymbolSmall::try_from(v.val) { - ScVal::try_from(ss).unwrap() - } else { - let e: Env = v.env.clone().try_into().unwrap(); - ScVal::try_from_val(&e, &v.to_val()).unwrap() - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl From for ScVal { - fn from(v: Symbol) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for ScVal { - type Error = ConversionError; - fn try_from_val(_e: &Env, v: &Symbol) -> Result { - Ok(v.into()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Symbol { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok(SymbolVal::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Symbol { - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScSymbol) -> Result { - Ok(SymbolVal::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl Symbol { - /// Creates a new Symbol given a string with valid characters. - /// - /// Valid characters are `a-zA-Z0-9_` and maximum string length is 32 - /// characters. - /// - /// Use `symbol_short!` for constant symbols that are 9 characters or less. - /// - /// Use `Symbol::try_from_val(env, s)`/`s.try_into_val(env)` in case if - /// failures need to be handled gracefully. - /// - /// ### Panics - /// - /// When the input string is not representable by Symbol. - pub fn new(env: &Env, s: &str) -> Self { - Self { - env: env.clone().into(), - val: s.try_into_val(env).unwrap_optimized(), - } - } - - /// Creates a new Symbol given a short string with valid characters. - /// - /// Valid characters are `a-zA-Z0-9_` and maximum length is 9 characters. - /// - /// The conversion can happen at compile time if called in a const context, - /// such as: - /// - /// ```rust - /// # use soroban_sdk::Symbol; - /// const SYMBOL: Symbol = Symbol::short("abcde"); - /// ``` - /// - /// Note that when called from a non-const context the conversion will occur - /// at runtime and the conversion logic will add considerable number of - /// bytes to built wasm file. For this reason the function should be generally - /// avoided: - /// - /// ```rust - /// # use soroban_sdk::Symbol; - /// let SYMBOL: Symbol = Symbol::short("abcde"); // AVOID! - /// ``` - /// - /// Instead use the `symbol_short!()` macro that will ensure the conversion always occurs in a const-context: - /// - /// ```rust - /// # use soroban_sdk::{symbol_short, Symbol}; - /// let SYMBOL: Symbol = symbol_short!("abcde"); // 👍 - /// ``` - /// - /// ### Panics - /// - /// When the input string is not representable by Symbol. - #[doc(hidden)] - #[deprecated(note = "use [symbol_short!()]")] - pub const fn short(s: &str) -> Self { - if let Ok(sym) = SymbolSmall::try_from_str(s) { - Symbol { - env: MaybeEnv::none(), - val: SymbolVal::from_small(sym), - } - } else { - panic!("short symbols are limited to 9 characters"); - } - } - - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, val: SymbolVal) -> Self { - Self { - env: env.into(), - val, - } - } - - pub fn as_val(&self) -> &Val { - self.val.as_val() - } - - pub fn to_val(&self) -> Val { - self.val.to_val() - } - - pub fn to_symbol_val(&self) -> SymbolVal { - self.val - } -} - -#[cfg(not(target_family = "wasm"))] -extern crate std; -#[cfg(not(target_family = "wasm"))] -impl ToString for Symbol { - fn to_string(&self) -> String { - if let Ok(s) = SymbolSmall::try_from(self.val) { - s.to_string() - } else { - let e: Env = self.env.clone().try_into().unwrap_optimized(); - SymbolStr::try_from_val(&e, &self.val) - .unwrap_optimized() - .to_string() - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/tests.rs b/temp_sdk/soroban-sdk-26.0.1/src/tests.rs deleted file mode 100644 index 6783954..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/tests.rs +++ /dev/null @@ -1,55 +0,0 @@ -#![cfg(test)] - -mod address; -mod address_payload; -mod auth; -mod bytes_alloc_vec; -mod bytes_buffer; -mod bytes_slice; -mod bytesn; -mod cmp_across_env_in_tests; -mod contract_add_i32; -mod contract_assert; -mod contract_custom_account_impl; -mod contract_docs; -mod contract_duration; -mod contract_event; -mod contract_fn; -mod contract_invoke; -mod contract_invoke_arg_count; -mod contract_meta; -mod contract_overlapping_type_fn_names; -mod contract_snapshot; -mod contract_store; -mod contract_timepoint; -mod contract_udt_enum; -mod contract_udt_enum_error; -mod contract_udt_enum_int; -mod contract_udt_enum_option; -mod contract_udt_option; -mod contract_udt_raw_identifier; -mod contract_udt_struct; -mod contract_udt_struct_tuple; -mod contractimpl_trait_call_resolution; -mod contractimport; -mod contractimport_with_error; -mod cost_estimate; -mod crypto_bls12_381; -mod crypto_bn254; -mod crypto_ed25519; -mod crypto_keccak256; -mod crypto_poseidon; -mod crypto_secp256k1; -mod crypto_secp256r1; -mod crypto_sha256; -mod env; -mod max_ttl; -mod muxed_address; -mod num_checked_arith; -mod prng; -mod prng_range; -mod proptest_scval_cmp; -mod proptest_val_cmp; -mod storage_testutils; -mod token_client; -mod vec_slice; diff --git a/temp_sdk/soroban-sdk-26.0.1/src/testutils.rs b/temp_sdk/soroban-sdk-26.0.1/src/testutils.rs deleted file mode 100644 index 2580fcf..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/testutils.rs +++ /dev/null @@ -1,798 +0,0 @@ -#![cfg(any(test, feature = "testutils"))] -#![cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))] - -//! Utilities intended for use when testing. - -pub mod arbitrary; - -mod sign; -use std::{fmt::Debug, rc::Rc}; - -pub use sign::ed25519; - -mod mock_auth; -pub use mock_auth::{ - AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthContract, MockAuthInvoke, -}; -use soroban_env_host::{TryFromVal, TryIntoVal}; - -pub mod storage; - -pub mod cost_estimate; - -use crate::{xdr, ConstructorArgs, Env, Val, Vec}; -use soroban_ledger_snapshot::LedgerSnapshot; - -pub use crate::env::EnvTestConfig; - -/// Trait for providing ledger data to the test environment. -/// -/// Implement this trait to create custom snapshot sources that load ledger state -/// from sources other than [`LedgerSnapshot`] files, such as RPC endpoints, -/// history archives, or in-memory data structures. -/// -/// Use with [`SnapshotSourceInput`] and [`Env::from_ledger_snapshot`] to initialize -/// a test environment from a custom source. -pub use crate::env::internal::storage::SnapshotSource; - -/// Error type returned by [`SnapshotSource::get`]. -/// -/// Required for implementing custom snapshot sources. -pub use crate::env::internal::HostError; - -pub trait Register { - fn register<'i, I, A>(self, env: &Env, id: I, args: A) -> crate::Address - where - I: Into>, - A: ConstructorArgs; -} - -impl Register for C -where - C: ContractFunctionSet + 'static, -{ - fn register<'i, I, A>(self, env: &Env, id: I, args: A) -> crate::Address - where - I: Into>, - A: ConstructorArgs, - { - env.register_contract_with_constructor(id, self, args) - } -} - -impl<'w> Register for &'w [u8] { - fn register<'i, I, A>(self, env: &Env, id: I, args: A) -> crate::Address - where - I: Into>, - A: ConstructorArgs, - { - env.register_contract_wasm_with_constructor(id, self, args) - } -} - -#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct Snapshot { - pub generators: Generators, - pub auth: AuthSnapshot, - pub ledger: LedgerSnapshot, - pub events: EventsSnapshot, -} - -impl Snapshot { - // Read in a [`Snapshot`] from a reader. - pub fn read(r: impl std::io::Read) -> Result { - Ok(serde_json::from_reader::<_, Snapshot>(r)?) - } - - // Read in a [`Snapshot`] from a file. - pub fn read_file(p: impl AsRef) -> Result { - let reader = std::io::BufReader::new(std::fs::File::open(p)?); - Self::read(reader) - } - - // Write a [`Snapshot`] to a writer. - pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { - Ok(serde_json::to_writer_pretty(w, self)?) - } - - // Write a [`Snapshot`] to file. - pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { - let p = p.as_ref(); - if let Some(dir) = p.parent() { - if !dir.exists() { - std::fs::create_dir_all(dir)?; - } - } - self.write(std::fs::File::create(p)?) - } -} - -#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct EventsSnapshot(pub std::vec::Vec); - -impl EventsSnapshot { - // Read in a [`EventsSnapshot`] from a reader. - pub fn read(r: impl std::io::Read) -> Result { - Ok(serde_json::from_reader::<_, EventsSnapshot>(r)?) - } - - // Read in a [`EventsSnapshot`] from a file. - pub fn read_file(p: impl AsRef) -> Result { - let reader = std::io::BufReader::new(std::fs::File::open(p)?); - Self::read(reader) - } - - // Write a [`EventsSnapshot`] to a writer. - pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { - Ok(serde_json::to_writer_pretty(w, self)?) - } - - // Write a [`EventsSnapshot`] to file. - pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { - let p = p.as_ref(); - if let Some(dir) = p.parent() { - if !dir.exists() { - std::fs::create_dir_all(dir)?; - } - } - self.write(std::fs::File::create(p)?) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct EventSnapshot { - pub event: xdr::ContractEvent, - pub failed_call: bool, -} - -impl From for EventSnapshot { - fn from(v: crate::env::internal::events::HostEvent) -> Self { - Self { - event: v.event, - failed_call: v.failed_call, - } - } -} - -#[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct AuthSnapshot( - pub std::vec::Vec>, -); - -impl AuthSnapshot { - // Read in a [`AuthSnapshot`] from a reader. - pub fn read(r: impl std::io::Read) -> Result { - Ok(serde_json::from_reader::<_, AuthSnapshot>(r)?) - } - - // Read in a [`AuthSnapshot`] from a file. - pub fn read_file(p: impl AsRef) -> Result { - let reader = std::io::BufReader::new(std::fs::File::open(p)?); - Self::read(reader) - } - - // Write a [`AuthSnapshot`] to a writer. - pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { - Ok(serde_json::to_writer_pretty(w, self)?) - } - - // Write a [`AuthSnapshot`] to file. - pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { - let p = p.as_ref(); - if let Some(dir) = p.parent() { - if !dir.exists() { - std::fs::create_dir_all(dir)?; - } - } - self.write(std::fs::File::create(p)?) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct Generators { - address: u64, - nonce: i64, - mux_id: u64, -} - -impl Default for Generators { - fn default() -> Generators { - Generators { - address: 0, - nonce: 0, - mux_id: 0, - } - } -} - -impl Generators { - // Read in a [`Generators`] from a reader. - pub fn read(r: impl std::io::Read) -> Result { - Ok(serde_json::from_reader::<_, Generators>(r)?) - } - - // Read in a [`Generators`] from a file. - pub fn read_file(p: impl AsRef) -> Result { - let reader = std::io::BufReader::new(std::fs::File::open(p)?); - Self::read(reader) - } - - // Write a [`Generators`] to a writer. - pub fn write(&self, w: impl std::io::Write) -> Result<(), std::io::Error> { - Ok(serde_json::to_writer_pretty(w, self)?) - } - - // Write a [`Generators`] to file. - pub fn write_file(&self, p: impl AsRef) -> Result<(), std::io::Error> { - let p = p.as_ref(); - if let Some(dir) = p.parent() { - if !dir.exists() { - std::fs::create_dir_all(dir)?; - } - } - self.write(std::fs::File::create(p)?) - } -} - -impl Generators { - pub fn address(&mut self) -> [u8; 32] { - self.address = self.address.checked_add(1).unwrap(); - let b: [u8; 8] = self.address.to_be_bytes(); - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b[0], b[1], - b[2], b[3], b[4], b[5], b[6], b[7], - ] - } - - pub fn nonce(&mut self) -> i64 { - self.nonce = self.nonce.checked_add(1).unwrap(); - self.nonce - } - - pub fn mux_id(&mut self) -> u64 { - self.mux_id = self.mux_id.checked_add(1).unwrap(); - self.mux_id - } -} - -#[doc(hidden)] -pub type ContractFunctionF = dyn Send + Sync + Fn(Env, &[Val]) -> Val; -#[doc(hidden)] -pub trait ContractFunctionRegister { - fn register(name: &'static str, func: &'static ContractFunctionF); -} -#[doc(hidden)] -pub trait ContractFunctionSet { - fn call(&self, func: &str, env: Env, args: &[Val]) -> Option; -} - -#[doc(inline)] -pub use crate::env::internal::LedgerInfo; - -/// Returns a default `LedgerInfo` suitable for testing. -pub(crate) fn default_ledger_info() -> LedgerInfo { - LedgerInfo { - protocol_version: 26, - sequence_number: 0, - timestamp: 0, - network_id: [0; 32], - base_reserve: 0, - min_persistent_entry_ttl: 4096, - min_temp_entry_ttl: 16, - max_entry_ttl: 6_312_000, - } -} - -/// Test utilities for [`Ledger`][crate::ledger::Ledger]. -pub trait Ledger { - /// Set ledger info. - fn set(&self, l: LedgerInfo); - - /// Sets the protocol version. - fn set_protocol_version(&self, protocol_version: u32); - - /// Sets the sequence number. - fn set_sequence_number(&self, sequence_number: u32); - - /// Sets the timestamp. - fn set_timestamp(&self, timestamp: u64); - - /// Sets the network ID. - fn set_network_id(&self, network_id: [u8; 32]); - - /// Sets the base reserve. - fn set_base_reserve(&self, base_reserve: u32); - - /// Sets the minimum temporary entry time-to-live. - fn set_min_temp_entry_ttl(&self, min_temp_entry_ttl: u32); - - /// Sets the minimum persistent entry time-to-live. - fn set_min_persistent_entry_ttl(&self, min_persistent_entry_ttl: u32); - - /// Sets the maximum entry time-to-live. - fn set_max_entry_ttl(&self, max_entry_ttl: u32); - - /// Get ledger info. - fn get(&self) -> LedgerInfo; - - /// Modify the ledger info. - fn with_mut(&self, f: F) - where - F: FnMut(&mut LedgerInfo); -} - -pub mod budget { - use core::fmt::{Debug, Display}; - - #[doc(inline)] - use crate::env::internal::budget::CostTracker; - #[doc(inline)] - pub use crate::xdr::ContractCostType; - - /// Budget that tracks the resources consumed for the environment. - /// - /// The budget consists of two cost dimensions: - /// - CPU instructions - /// - Memory - /// - /// Inputs feed into those cost dimensions. - /// - /// Note that all cost dimensions – CPU instructions, memory – and the VM - /// cost type inputs are likely to be underestimated when running Rust code - /// compared to running the WASM equivalent. - /// - /// ### Examples - /// - /// ``` - /// use soroban_sdk::{Env, Symbol}; - /// - /// # #[cfg(feature = "testutils")] - /// # fn main() { - /// # let env = Env::default(); - /// env.cost_estimate().budget().reset_default(); - /// // ... - /// println!("{}", env.cost_estimate().budget()); - /// # } - /// # #[cfg(not(feature = "testutils"))] - /// # fn main() { } - /// ``` - pub struct Budget(pub(crate) crate::env::internal::budget::Budget); - - impl Display for Budget { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - writeln!(f, "{}", self.0) - } - } - - impl Debug for Budget { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - writeln!(f, "{:?}", self.0) - } - } - - impl Budget { - pub(crate) fn new(b: crate::env::internal::budget::Budget) -> Self { - Self(b) - } - - /// Reset the budget. - pub fn reset_default(&mut self) { - self.0.reset_default().unwrap(); - } - - pub fn reset_unlimited(&mut self) { - self.0.reset_unlimited().unwrap(); - } - - pub fn reset_limits(&mut self, cpu: u64, mem: u64) { - self.0.reset_limits(cpu, mem).unwrap(); - } - - pub fn reset_tracker(&mut self) { - self.0.reset_tracker().unwrap(); - } - - /// Returns the CPU instruction cost. - /// - /// Note that CPU instructions are likely to be underestimated when - /// running Rust code compared to running the WASM equivalent. - pub fn cpu_instruction_cost(&self) -> u64 { - self.0.get_cpu_insns_consumed().unwrap() - } - - /// Returns the memory cost. - /// - /// Note that memory is likely to be underestimated when running Rust - /// code compared to running the WASM equivalent. - pub fn memory_bytes_cost(&self) -> u64 { - self.0.get_mem_bytes_consumed().unwrap() - } - - /// Get the cost tracker associated with the cost type. The tracker - /// tracks the cumulative iterations and inputs and derived cpu and - /// memory. If the underlying model is a constant model, then inputs is - /// `None` and only iterations matter. - /// - /// Note that VM cost types are likely to be underestimated when running - /// natively as Rust code inside tests code compared to running the WASM - /// equivalent. - pub fn tracker(&self, cost_type: ContractCostType) -> CostTracker { - self.0.get_tracker(cost_type).unwrap() - } - - /// Print the budget costs and inputs to stdout. - pub fn print(&self) { - println!("{}", self.0); - } - } -} - -#[derive(Clone)] -pub struct ContractEvents { - env: Env, - events: std::vec::Vec, -} - -impl ContractEvents { - pub(crate) fn new(env: &Env, events: std::vec::Vec) -> Self { - ContractEvents { - env: env.clone(), - events, - } - } - - /// Returns the events in their XDR form. - pub fn events(&self) -> &[xdr::ContractEvent] { - &self.events - } - - /// Creates a new ContractEvents struct that only includes events emitted - /// by the provided contract address. - pub fn filter_by_contract(&self, addr: &crate::Address) -> Self { - let contract_id = Some(addr.contract_id()); - let filtered_events = self - .events - .iter() - .filter(|e| e.contract_id == contract_id) - .cloned() - .collect(); - Self::new(&self.env, filtered_events) - } -} - -impl Eq for ContractEvents {} - -impl PartialEq for ContractEvents { - fn eq(&self, other: &ContractEvents) -> bool { - self.events == other.events - } -} - -impl PartialEq> for ContractEvents { - fn eq(&self, other: &std::vec::Vec) -> bool { - self.events == *other - } -} - -impl PartialEq<&[xdr::ContractEvent]> for ContractEvents { - fn eq(&self, other: &&[xdr::ContractEvent]) -> bool { - self.events == *other - } -} - -impl PartialEq<[xdr::ContractEvent; N]> for ContractEvents { - fn eq(&self, other: &[xdr::ContractEvent; N]) -> bool { - self.events == other - } -} - -impl PartialEq, Val)>> for ContractEvents { - fn eq(&self, other: &Vec<(crate::Address, Vec, Val)>) -> bool { - let len = match u32::try_from(self.events.len()) { - Ok(len) => len, - Err(..) => return false, - }; - if len != other.len() { - return false; - } - - for (event, (contract_id, topics, data)) in self.events.iter().zip(other.iter()) { - let data_xdr = match xdr::ScVal::try_from_val(&self.env, &data) { - Ok(data_xdr) => data_xdr, - Err(..) => return false, - }; - let as_xdr = xdr::ContractEvent { - ext: xdr::ExtensionPoint::V0, - type_: xdr::ContractEventType::Contract, - contract_id: Some(contract_id.contract_id()), - body: xdr::ContractEventBody::V0(xdr::ContractEventV0 { - topics: topics.into(), - data: data_xdr, - }), - }; - if event != &as_xdr { - return false; - } - } - true - } -} - -impl Debug for ContractEvents { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self.events) - } -} - -/// Test utilities for [`Events`][crate::events::Events]. -pub trait Events { - /// Returns all contract events that have been published by the last contract - /// invocation. If the last contract invocation failed, no events are returned. - /// - /// Events are returned in the order they were published, with the - /// last published event being the last in the list. - /// - /// Returns a [`ContractEvents`] struct that contains: - /// - The test Env - /// - A vector of events emitted by successful contract invocations - fn all(&self) -> ContractEvents; -} - -/// Test utilities for [`Logs`][crate::logs::Logs]. -pub trait Logs { - /// Returns all diagnostic events that have been logged. - fn all(&self) -> std::vec::Vec; - /// Prints all diagnostic events to stdout. - fn print(&self); -} - -/// Test utilities for [`BytesN`][crate::BytesN]. -pub trait BytesN { - // Generate a BytesN filled with random bytes. - // - // The value filled is not cryptographically secure. - fn random(env: &Env) -> crate::BytesN; -} - -/// Generates an array of N random bytes. -/// -/// The value returned is not cryptographically secure. -pub(crate) fn random() -> [u8; N] { - use rand::RngCore; - let mut arr = [0u8; N]; - rand::thread_rng().fill_bytes(&mut arr); - arr -} - -pub trait Address { - /// Generate a new Address. - /// - /// Implementation note: this always builds the contract addresses now. This - /// shouldn't normally matter though, as contracts should be agnostic to - /// the underlying Address value. - fn generate(env: &Env) -> crate::Address; -} - -pub trait MuxedAddress { - /// Create a new MuxedAddress with arbitrary `Address` and id parts. - /// - /// Note, that since currently only accounts can be multiplexed, the - /// underlying `Address` will be an account (not contract) address. - fn generate(env: &Env) -> crate::MuxedAddress; - - /// Returns a new `MuxedAddress` that has the same `Address` part as the - /// provided `address` and the provided multiplexing id. - /// - /// `address` can be either an `Address` or `MuxedAddress` and it has to - /// be an account (non-contract) address. - /// - /// Note on usage: the simplest way to test `MuxedAddress` is to generate - /// an arbitrary valid address with `MuxedAddress::generate`, then - /// `MuxedAddress::new` can be used to alter only the multiplexing id part - /// of that address. - fn new>(address: T, id: u64) -> crate::MuxedAddress; -} - -pub trait Deployer { - /// Gets the TTL of the given contract's instance. - /// - /// TTL is the number of ledgers left until the instance entry is considered - /// expired, excluding the current ledger. - /// - /// Panics if there is no instance corresponding to the provided address, - /// or if the instance has expired. - fn get_contract_instance_ttl(&self, contract: &crate::Address) -> u32; - - /// Gets the TTL of the given contract's Wasm code entry. - /// - /// TTL is the number of ledgers left until the contract code entry - /// is considered expired, excluding the current ledger. - /// - /// Panics if there is no contract instance/code corresponding to - /// the provided address, or if the instance/code has expired. - fn get_contract_code_ttl(&self, contract: &crate::Address) -> u32; -} - -pub use xdr::AccountFlags as IssuerFlags; - -#[derive(Clone)] -pub struct StellarAssetIssuer { - env: Env, - account_id: xdr::AccountId, -} - -impl StellarAssetIssuer { - pub(crate) fn new(env: Env, account_id: xdr::AccountId) -> Self { - Self { env, account_id } - } - - /// Returns the flags for the issuer. - pub fn flags(&self) -> u32 { - let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount { - account_id: self.account_id.clone(), - })); - - let (entry, _) = self.env.host().get_ledger_entry(&k).unwrap().unwrap(); - - match &entry.data { - xdr::LedgerEntryData::Account(e) => e.flags, - _ => panic!("expected account entry but got {:?}", entry.data), - } - } - - /// Adds the flag specified to the existing issuer flags - pub fn set_flag(&self, flag: IssuerFlags) { - self.overwrite_issuer_flags(self.flags() | (flag as u32)) - } - - /// Clears the flag specified from the existing issuer flags - pub fn clear_flag(&self, flag: IssuerFlags) { - self.overwrite_issuer_flags(self.flags() & (!(flag as u32))) - } - - pub fn address(&self) -> crate::Address { - xdr::ScAddress::Account(self.account_id.clone()) - .try_into_val(&self.env.clone()) - .unwrap() - } - - /// Sets the issuer flags field. - /// Each flag is a bit with values corresponding to [xdr::AccountFlags] - /// - /// Use this to test interactions between trustlines/balances and the issuer flags. - fn overwrite_issuer_flags(&self, flags: u32) { - if u64::from(flags) > xdr::MASK_ACCOUNT_FLAGS_V17 { - panic!( - "issuer flags value must be at most {}", - xdr::MASK_ACCOUNT_FLAGS_V17 - ); - } - - let k = Rc::new(xdr::LedgerKey::Account(xdr::LedgerKeyAccount { - account_id: self.account_id.clone(), - })); - - let (entry, _) = self.env.host().get_ledger_entry(&k).unwrap().unwrap(); - let mut entry = entry.as_ref().clone(); - - match entry.data { - xdr::LedgerEntryData::Account(ref mut e) => e.flags = flags, - _ => panic!("expected account entry but got {:?}", entry.data), - } - - self.env - .host() - .add_ledger_entry(&k, &Rc::new(entry), None) - .unwrap(); - } -} - -pub struct StellarAssetContract { - address: crate::Address, - issuer: StellarAssetIssuer, - asset: xdr::Asset, -} - -impl StellarAssetContract { - pub(crate) fn new( - address: crate::Address, - issuer: StellarAssetIssuer, - asset: xdr::Asset, - ) -> Self { - Self { - address, - issuer, - asset, - } - } - - pub fn address(&self) -> crate::Address { - self.address.clone() - } - - pub fn issuer(&self) -> StellarAssetIssuer { - self.issuer.clone() - } - - #[doc(hidden)] - pub fn asset(&self) -> xdr::Asset { - self.asset.clone() - } -} - -/// Input for creating an [`Env`] from a custom snapshot source. -/// -/// This struct enables [`Env::from_ledger_snapshot`] to accept custom snapshot -/// source types beyond [`LedgerSnapshot`], providing flexibility for testing -/// scenarios that load ledger state from different sources such as RPC endpoints, -/// history archives, or in-memory data structures. -/// -/// # Fields -/// -/// * `source` - A snapshot source implementing the [`SnapshotSource`] trait. -/// This is used to load ledger entries on demand during test execution. -/// -/// * `ledger_info` - Optional ledger info to initialize the environment with. -/// If `None`, default test ledger info is used. -/// -/// * `snapshot` - Optional [`LedgerSnapshot`] used as the base for capturing -/// state changes. When the test completes, modified entries are written to -/// this snapshot. If `None`, a new empty snapshot is created. -/// -/// # Example -/// -/// ``` -/// use soroban_sdk::testutils::{SnapshotSource, SnapshotSourceInput, HostError}; -/// use soroban_sdk::xdr::{LedgerEntry, LedgerKey}; -/// use soroban_sdk::Env; -/// use std::rc::Rc; -/// -/// struct MyCustomSource; -/// -/// impl SnapshotSource for MyCustomSource { -/// fn get( -/// &self, -/// key: &Rc, -/// ) -> Result, Option)>, HostError> { -/// // Return None for keys not found, or Some((entry, live_until_ledger)) -/// Ok(None) -/// } -/// } -/// -/// let input = SnapshotSourceInput { -/// source: Rc::new(MyCustomSource), -/// ledger_info: None, -/// snapshot: None, -/// }; -/// let env = Env::from_ledger_snapshot(input); -/// ``` -pub struct SnapshotSourceInput { - pub source: Rc, - pub ledger_info: Option, - pub snapshot: Option>, -} - -/// Converts a [`LedgerSnapshot`] into a [`SnapshotSourceInput`]. -/// -/// This conversion maintains backward compatibility with the existing API, -/// allowing [`LedgerSnapshot`] to be used directly with [`Env::from_ledger_snapshot`]. -/// -/// The [`LedgerSnapshot`] is wrapped in an [`Rc`] and used for all three fields: -/// - As the snapshot source for loading ledger entries -/// - To provide the ledger info for the environment -/// - As the base snapshot for capturing state changes -impl From for SnapshotSourceInput { - fn from(s: LedgerSnapshot) -> Self { - let s = Rc::new(s); - Self { - source: s.clone(), - ledger_info: Some(s.ledger_info()), - snapshot: Some(s), - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/token.rs b/temp_sdk/soroban-sdk-26.0.1/src/token.rs deleted file mode 100644 index c9d2bd4..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/token.rs +++ /dev/null @@ -1,491 +0,0 @@ -//! Token contains types for calling and accessing token contracts, including -//! the Stellar Asset Contract. -//! -//! See [`TokenInterface`] for the interface of token contracts such as the -//! Stellar Asset Contract. -//! -//! Use [`TokenClient`] for calling token contracts such as the Stellar Asset -//! Contract. - -use crate::{contracttrait, Address, Env, MuxedAddress, String}; - -// The interface below was copied from -// https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/native_contract/token/contract.rs -// at commit b3c188f48dec51a956c1380fb6fe92201a3f716b. -// -// Differences between this interface and the built-in contract -// 1. The return values here don't return Results. -// 2. The implementations have been replaced with a panic. -// 3. &Host type usage are replaced with Env - -#[doc(hidden)] -#[deprecated(note = "use TokenInterface")] -pub use TokenInterface as Interface; - -#[doc(hidden)] -#[deprecated(note = "use TokenClient")] -pub use TokenClient as Client; - -/// Interface for Token contracts, such as the Stellar Asset Contract. -/// -/// Defined by [SEP-41]. -/// -/// [SEP-41]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0041.md -/// -/// The token interface provides the following functionality. -/// -/// If a contract implementing the interface does not support some of the -/// functionality, it should return an error. -/// -/// The interface does not define any set of standard errors. Errors can be -/// defined by the implementing contract. -/// -/// ## Meta -/// -/// Tokens implementing the interface expose meta functions about the token: -/// - [`decimals`][Self::decimals] -/// - [`name`][Self::name] -/// - [`symbol`][Self::symbol] -/// -/// ## Balances -/// -/// Tokens track a balance for each address that holds the token. Tokens implementing the interface expose -/// a single function for getting the balance that an address holds: -/// - [`balance`][Self::balance] -/// -/// ## Transfers -/// -/// Tokens allow holders of the token to transfer tokens to other addresses. -/// Tokens implementing the interface expose a single function for doing so: -/// - [`transfer`][Self::transfer] -/// -/// ## Burning -/// -/// Tokens allow holders of the token to burn, i.e. dispose of, tokens without -/// transferring them to another holder. Tokens implementing the interface -/// expose a single function for doing so: -/// - [`burn`][Self::burn] -/// -/// ## Allowances -/// -/// Tokens can allow holders to permit others to transfer amounts from their -/// balance using the following functions. -/// - [`allowance`][Self::allowance] -/// - [`approve`][Self::approve] -/// - [`transfer_from`][Self::transfer_from] -/// - [`burn_from`][Self::burn_from] -/// -/// ## Minting -/// -/// There are no functions in the token interface for minting tokens. Minting is -/// an administrative function that can differ significantly from one token to -/// the next. -#[contracttrait( - crate_path = "crate", - spec_name = "TokenFnSpec", - spec_export = false, - args_name = "TokenArgs", - client_name = "TokenClient" -)] -pub trait TokenInterface { - /// Returns the allowance for `spender` to transfer from `from`. - /// - /// The amount returned is the amount that spender is allowed to transfer - /// out of from's balance. When the spender transfers amounts, the allowance - /// will be reduced by the amount transferred. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens to be drawn from. - /// * `spender` - The address spending the tokens held by `from`. - fn allowance(env: Env, from: Address, spender: Address) -> i128; - - /// Set the allowance by `amount` for `spender` to transfer/burn from - /// `from`. - /// - /// The amount set is the amount that spender is approved to transfer out of - /// from's balance. The spender will be allowed to transfer amounts, and - /// when an amount is transferred the allowance will be reduced by the - /// amount transferred. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens to be drawn from. - /// * `spender` - The address being authorized to spend the tokens held by - /// `from`. - /// * `amount` - The tokens to be made available to `spender`. - /// * `expiration_ledger` - The ledger number where this allowance expires. Cannot - /// be less than the current ledger number unless the amount is being set to 0. - /// An expired entry (where expiration_ledger < the current ledger number) - /// should be treated as a 0 amount allowance. - /// - /// # Events - /// - /// Emits an event with topics `["approve", from: Address, - /// spender: Address], data = [amount: i128, expiration_ledger: u32]` - fn approve(env: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32); - - /// Returns the balance of `id`. - /// - /// # Arguments - /// - /// * `id` - The address for which a balance is being queried. If the - /// address has no existing balance, returns 0. - fn balance(env: Env, id: Address) -> i128; - - /// Transfer `amount` from `from` to `to`. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens which will be - /// withdrawn from. - /// * `to` - The address which will receive the transferred tokens. - /// * `amount` - The amount of tokens to be transferred. - /// - /// # Events - /// - /// Emits an event with: - /// * topics `["transfer", from: Address, to: Address]` - /// * data `{ to_muxed_id: Option, amount: i128 }: Map` - /// - /// Legacy implementations may emit an event with: - /// * topics `["transfer", from: Address, to: Address]` - /// * data `amount: i128` - fn transfer(env: Env, from: Address, to: MuxedAddress, amount: i128); - - /// Transfer `amount` from `from` to `to`, consuming the allowance that - /// `spender` has on `from`'s balance. Authorized by spender - /// (`spender.require_auth()`). - /// - /// The spender will be allowed to transfer the amount from from's balance - /// if the amount is less than or equal to the allowance that the spender - /// has on the from's balance. The spender's allowance on from's balance - /// will be reduced by the amount. - /// - /// # Arguments - /// - /// * `spender` - The address authorizing the transfer, and having its - /// allowance consumed during the transfer. - /// * `from` - The address holding the balance of tokens which will be - /// withdrawn from. - /// * `to` - The address which will receive the transferred tokens. - /// * `amount` - The amount of tokens to be transferred. - /// - /// # Events - /// - /// Emits an event with topics `["transfer", from: Address, to: Address], - /// data = amount: i128` - fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128); - - /// Burn `amount` from `from`. - /// - /// Reduces from's balance by the amount, without transferring the balance - /// to another holder's balance. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens which will be - /// burned from. - /// * `amount` - The amount of tokens to be burned. - /// - /// # Events - /// - /// Emits an event with topics `["burn", from: Address], data = amount: - /// i128` - fn burn(env: Env, from: Address, amount: i128); - - /// Burn `amount` from `from`, consuming the allowance of `spender`. - /// - /// Reduces from's balance by the amount, without transferring the balance - /// to another holder's balance. - /// - /// The spender will be allowed to burn the amount from from's balance, if - /// the amount is less than or equal to the allowance that the spender has - /// on the from's balance. The spender's allowance on from's balance will be - /// reduced by the amount. - /// - /// # Arguments - /// - /// * `spender` - The address authorizing the burn, and having its allowance - /// consumed during the burn. - /// * `from` - The address holding the balance of tokens which will be - /// burned from. - /// * `amount` - The amount of tokens to be burned. - /// - /// # Events - /// - /// Emits an event with topics `["burn", from: Address], data = amount: - /// i128` - fn burn_from(env: Env, spender: Address, from: Address, amount: i128); - - /// Returns the number of decimals used to represent amounts of this token. - /// - /// # Panics - /// - /// If the contract has not yet been initialized. - fn decimals(env: Env) -> u32; - - /// Returns the name for this token. - /// - /// # Panics - /// - /// If the contract has not yet been initialized. - fn name(env: Env) -> String; - - /// Returns the symbol for this token. - /// - /// # Panics - /// - /// If the contract has not yet been initialized. - fn symbol(env: Env) -> String; -} - -/// Interface for admin capabilities for Token contracts, such as the Stellar -/// Asset Contract. -#[contracttrait( - crate_path = "crate", - spec_name = "StellarAssetFnSpec", - spec_export = false, - args_name = "StellarAssetArgs", - client_name = "StellarAssetClient" -)] -pub trait StellarAssetInterface { - /// Returns the allowance for `spender` to transfer from `from`. - /// - /// The amount returned is the amount that spender is allowed to transfer - /// out of from's balance. When the spender transfers amounts, the allowance - /// will be reduced by the amount transferred. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens to be drawn from. - /// * `spender` - The address spending the tokens held by `from`. - fn allowance(env: Env, from: Address, spender: Address) -> i128; - - /// Set the allowance by `amount` for `spender` to transfer/burn from - /// `from`. - /// - /// The amount set is the amount that spender is approved to transfer out of - /// from's balance. The spender will be allowed to transfer amounts, and - /// when an amount is transferred the allowance will be reduced by the - /// amount transferred. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens to be drawn from. - /// * `spender` - The address being authorized to spend the tokens held by - /// `from`. - /// * `amount` - The tokens to be made available to `spender`. - /// * `expiration_ledger` - The ledger number where this allowance expires. Cannot - /// be less than the current ledger number unless the amount is being set to 0. - /// An expired entry (where expiration_ledger < the current ledger number) - /// should be treated as a 0 amount allowance. - /// - /// # Events - /// - /// Emits an event with topics `["approve", from: Address, - /// spender: Address], data = [amount: i128, expiration_ledger: u32]` - fn approve(env: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32); - - /// Returns the balance of `id`. - /// - /// # Arguments - /// - /// * `id` - The address for which a balance is being queried. If the - /// address has no existing balance, returns 0. - fn balance(env: Env, id: Address) -> i128; - - /// Transfer `amount` from `from` to `to`. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens which will be - /// withdrawn from. - /// * `to` - The address which will receive the transferred tokens. - /// * `amount` - The amount of tokens to be transferred. - /// - /// # Events - /// - /// Emits an event with: - /// * topics `["transfer", from: Address, to: Address]` - /// * data `{ to_muxed_id: Option, amount: i128 }: Map` - /// - /// Legacy implementations may emit an event with: - /// * topics `["transfer", from: Address, to: Address]` - /// * data `amount: i128` - fn transfer(env: Env, from: Address, to: MuxedAddress, amount: i128); - - /// Transfer `amount` from `from` to `to`, consuming the allowance that - /// `spender` has on `from`'s balance. Authorized by spender - /// (`spender.require_auth()`). - /// - /// The spender will be allowed to transfer the amount from from's balance - /// if the amount is less than or equal to the allowance that the spender - /// has on the from's balance. The spender's allowance on from's balance - /// will be reduced by the amount. - /// - /// # Arguments - /// - /// * `spender` - The address authorizing the transfer, and having its - /// allowance consumed during the transfer. - /// * `from` - The address holding the balance of tokens which will be - /// withdrawn from. - /// * `to` - The address which will receive the transferred tokens. - /// * `amount` - The amount of tokens to be transferred. - /// - /// # Events - /// - /// Emits an event with topics `["transfer", from: Address, to: Address], - /// data = amount: i128` - fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128); - - /// Burn `amount` from `from`. - /// - /// Reduces from's balance by the amount, without transferring the balance - /// to another holder's balance. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance of tokens which will be - /// burned from. - /// * `amount` - The amount of tokens to be burned. - /// - /// # Events - /// - /// Emits an event with topics `["burn", from: Address], data = amount: - /// i128` - fn burn(env: Env, from: Address, amount: i128); - - /// Burn `amount` from `from`, consuming the allowance of `spender`. - /// - /// Reduces from's balance by the amount, without transferring the balance - /// to another holder's balance. - /// - /// The spender will be allowed to burn the amount from from's balance, if - /// the amount is less than or equal to the allowance that the spender has - /// on the from's balance. The spender's allowance on from's balance will be - /// reduced by the amount. - /// - /// # Arguments - /// - /// * `spender` - The address authorizing the burn, and having its allowance - /// consumed during the burn. - /// * `from` - The address holding the balance of tokens which will be - /// burned from. - /// * `amount` - The amount of tokens to be burned. - /// - /// # Events - /// - /// Emits an event with topics `["burn", from: Address], data = amount: - /// i128` - fn burn_from(env: Env, spender: Address, from: Address, amount: i128); - - /// Returns the number of decimals used to represent amounts of this token. - /// - /// # Panics - /// - /// If the contract has not yet been initialized. - fn decimals(env: Env) -> u32; - - /// Returns the name for this token. - /// - /// # Panics - /// - /// If the contract has not yet been initialized. - fn name(env: Env) -> String; - - /// Returns the symbol for this token. - /// - /// # Panics - /// - /// If the contract has not yet been initialized. - fn symbol(env: Env) -> String; - - /// Sets the administrator to the specified address `new_admin`. - /// - /// # Arguments - /// - /// * `new_admin` - The address which will henceforth be the administrator - /// of this token contract. - /// - /// # Events - /// - /// Emits an event with topics `["set_admin", admin: Address], data = - /// [new_admin: Address]` - fn set_admin(env: Env, new_admin: Address); - - /// Returns the admin of the contract. - /// - /// # Panics - /// - /// If the admin is not set. - fn admin(env: Env) -> Address; - - /// Sets whether the account is authorized to use its balance. If - /// `authorized` is true, `id` should be able to use its balance. - /// - /// # Arguments - /// - /// * `id` - The address being (de-)authorized. - /// * `authorize` - Whether or not `id` can use its balance. - /// - /// # Events - /// - /// Emits an event with topics `["set_authorized", id: Address], data = - /// [authorize: bool]` - fn set_authorized(env: Env, id: Address, authorize: bool); - - /// Returns true if `id` is authorized to use its balance. - /// - /// # Arguments - /// - /// * `id` - The address for which token authorization is being checked. - fn authorized(env: Env, id: Address) -> bool; - - /// Mints `amount` to `to`. - /// - /// # Arguments - /// - /// * `to` - The address which will receive the minted tokens. - /// * `amount` - The amount of tokens to be minted. - /// - /// # Events - /// - /// Emits an event with topics `["mint", to: Address], data - /// = amount: i128` - fn mint(env: Env, to: Address, amount: i128); - - /// Clawback `amount` from `from` account. `amount` is burned in the - /// clawback process. - /// - /// # Arguments - /// - /// * `from` - The address holding the balance from which the clawback will - /// take tokens. - /// * `amount` - The amount of tokens to be clawed back. - /// - /// # Events - /// - /// Emits an event with topics `["clawback", admin: Address, to: Address], - /// data = amount: i128` - fn clawback(env: Env, from: Address, amount: i128); - - /// Creates this contract asset's unlimited trustline for the provided - /// address. - /// - /// This is a no-op if the input address is a C-address, or if the - /// provided G-address already has the respective trustline. - /// - /// If the trustline is actually created, this will require authorization - /// from `addr` (i.e. `addr.require_auth` will be called). - /// - /// # Arguments - /// - /// * `addr` - The address for which a trustline will be created. - /// - /// # Panics - /// - /// Panics during trustline creation if the asset issuer does not exist, - /// or when a new trustline cannot be created. - fn trust(env: Env, addr: Address); -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs b/temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs deleted file mode 100644 index 51f94d9..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/try_from_val_for_contract_fn.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! TryFromValForContractFn is an internal trait that is used by code generated -//! for the export of contract functions. The generated code calls the trait to -//! convert incoming Val's into their respective SDK types. -//! -//! The trait has a blanket implementation for all types that already implement -//! TryFromVal<_, Val>. -//! -//! The trait exists primarily to allow some special types, e.g. -//! [`crate::crypto::Hash`], to be used as inputs to contract functions without -//! otherwise being creatable from a Val via the public TryFromVal trait, and -//! therefore not storeable. -//! -//! For types that can be used and converted everywhere, implementing TryFromVal -//! is most appropriate. For types that should only be used and converted to as -//! part of contract function invocation, then this trait is appropriate. -//! -//! When the `experimental_spec_shaking_v2` feature is enabled, this trait also -//! calls `SpecShakingMarker::spec_shaking_marker()` to ensure that type specs -//! are included in the WASM when types are used at external boundaries. - -use crate::{env::internal::Env, Error, TryFromVal}; -use core::fmt::Debug; - -#[doc(hidden)] -#[deprecated( - note = "TryFromValForContractFn is an internal trait and is not safe to use or implement" -)] -pub trait TryFromValForContractFn: Sized { - type Error: Debug + Into; - fn try_from_val_for_contract_fn(env: &E, v: &V) -> Result; -} - -#[cfg(feature = "experimental_spec_shaking_v2")] -#[doc(hidden)] -#[allow(deprecated)] -impl TryFromValForContractFn for U -where - U: TryFromVal + crate::SpecShakingMarker, -{ - type Error = U::Error; - fn try_from_val_for_contract_fn(e: &E, v: &T) -> Result { - U::spec_shaking_marker(); - U::try_from_val(e, v) - } -} - -#[cfg(not(feature = "experimental_spec_shaking_v2"))] -#[doc(hidden)] -#[allow(deprecated)] -impl TryFromValForContractFn for U -where - U: TryFromVal, -{ - type Error = U::Error; - fn try_from_val_for_contract_fn(e: &E, v: &T) -> Result { - U::try_from_val(e, v) - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/tuple.rs b/temp_sdk/soroban-sdk-26.0.1/src/tuple.rs deleted file mode 100644 index 066021a..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/tuple.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! This module contains conversion helpers for tuple - -use crate::{vec, ConversionError, Env, IntoVal, Topics, TryFromVal, Val, Vec}; - -// Note that the way that this conversion of tuple to Vec is written results in a need for any -// supported type to support converting from `&&` (double-ref) to `Val`. This means values that -// convert to `Val` need to have an impl of TryFromVal converting not only from their owned value -// (which converts from a ref of that owned value), but from a & value (which converts from a -// double ref &&). -// -// This is why you'll see TryFromVal impls from &values, not just owned values. - -impl TryFromVal for Vec { - type Error = ConversionError; - - fn try_from_val(env: &Env, _v: &()) -> Result { - Ok(Vec::::new(env)) - } -} - -macro_rules! impl_into_vec_for_tuple { - ( $($typ:ident $idx:tt)* ) => { - impl<$($typ),*> TryFromVal for Vec - where - $($typ: IntoVal),* - { - type Error = ConversionError; - fn try_from_val(env: &Env, v: &($($typ,)*)) -> Result { - Ok(vec![&env, $(v.$idx.into_val(env), )*]) - } - } - }; -} -impl_into_vec_for_tuple! { T0 0 } -impl_into_vec_for_tuple! { T0 0 T1 1 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 } -impl_into_vec_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 } - -macro_rules! impl_topics_for_tuple { - ( $($typ:ident $idx:tt)* ) => { - impl<$($typ),*> Topics for ($($typ,)*) - where - $($typ: IntoVal),* - { - } - }; -} - -// 0 topics -impl Topics for () {} -// 1-13 topics -impl_topics_for_tuple! { T0 0 } -impl_topics_for_tuple! { T0 0 T1 1 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 } -impl_topics_for_tuple! { T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10 T11 11 T12 12 } diff --git a/temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs b/temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs deleted file mode 100644 index 73787cd..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/unwrap.rs +++ /dev/null @@ -1,96 +0,0 @@ -use core::convert::Infallible; - -pub trait UnwrapOptimized { - type Output; - fn unwrap_optimized(self) -> Self::Output; - fn expect_optimized(self, msg: &'static str) -> Self::Output; -} - -impl UnwrapOptimized for Option { - type Output = T; - - #[inline(always)] - fn unwrap_optimized(self) -> Self::Output { - #[cfg(target_family = "wasm")] - match self { - Some(t) => t, - None => core::arch::wasm32::unreachable(), - } - #[cfg(not(target_family = "wasm"))] - self.unwrap() - } - - #[inline(always)] - fn expect_optimized(self, _msg: &'static str) -> Self::Output { - #[cfg(target_family = "wasm")] - match self { - Some(t) => t, - None => core::arch::wasm32::unreachable(), - } - #[cfg(not(target_family = "wasm"))] - self.expect(_msg) - } -} - -impl UnwrapOptimized for Result { - type Output = T; - - #[inline(always)] - fn unwrap_optimized(self) -> Self::Output { - #[cfg(target_family = "wasm")] - match self { - Ok(t) => t, - Err(_) => core::arch::wasm32::unreachable(), - } - #[cfg(not(target_family = "wasm"))] - self.unwrap() - } - - #[inline(always)] - fn expect_optimized(self, _msg: &'static str) -> Self::Output { - #[cfg(target_family = "wasm")] - match self { - Ok(t) => t, - Err(_) => core::arch::wasm32::unreachable(), - } - #[cfg(not(target_family = "wasm"))] - self.expect(_msg) - } -} - -pub trait UnwrapInfallible { - type Output; - fn unwrap_infallible(self) -> Self::Output; -} - -impl UnwrapInfallible for Result { - type Output = T; - - fn unwrap_infallible(self) -> Self::Output { - match self { - Ok(ok) => ok, - // In the following `Err(never)` branch we convert a type from - // `Infallible` to `!`. Both of these are empty types and are - // essentially synonyms in rust, they differ only due to historical - // reasons that will eventually be eliminated. `Infallible` is a - // version we can put in a structure, and `!` is one that gets some - // special control-flow treatments. - // - // Specifically: the type `!` of the resulting expression will be - // considered an acceptable inhabitant of any type -- including - // `Self::Output` -- since it's an impossible path to execute, this - // is considered a harmless convenience in the type system, a bit - // like defining zero-divided-by-anything as zero. - // - // We could also write an infinite `loop {}` here or - // `unreachable!()` or similar expressions of type `!`, but - // destructuring the `never` variable into an empty set of cases is - // the most honest since it's statically checked to _be_ infallible, - // not just an assertion of our hopes.) - - // This allow and the Err can be removed once 1.82 becomes stable - #[allow(unreachable_patterns)] - Err(never) => match never {}, - } - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/vec.rs b/temp_sdk/soroban-sdk-26.0.1/src/vec.rs deleted file mode 100644 index 226c935..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/vec.rs +++ /dev/null @@ -1,2000 +0,0 @@ -use core::{ - borrow::Borrow, - cmp::Ordering, - convert::Infallible, - fmt::Debug, - iter::FusedIterator, - marker::PhantomData, - ops::{Bound, RangeBounds}, -}; - -use crate::{ - iter::{UnwrappedEnumerable, UnwrappedIter}, - unwrap::{UnwrapInfallible, UnwrapOptimized}, -}; - -use super::{ - env::internal::{Env as _, EnvBase as _, VecObject}, - ConversionError, Env, IntoVal, TryFromVal, TryIntoVal, Val, -}; - -#[cfg(doc)] -use crate::{storage::Storage, Bytes, BytesN, Map}; - -/// Create a [Vec] with the given items. -/// -/// The first argument in the list must be a reference to an [Env], then the -/// items follow. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{Env, vec}; -/// -/// let env = Env::default(); -/// let vec = vec![&env, 0, 1, 2, 3]; -/// assert_eq!(vec.len(), 4); -/// ``` -#[macro_export] -macro_rules! vec { - ($env:expr $(,)?) => { - $crate::Vec::new($env) - }; - ($env:expr, $($x:expr),+ $(,)?) => { - $crate::Vec::from_array($env, [$($x),+]) - }; -} - -/// Vec is a sequential and indexable growable collection type. -/// -/// Values are stored in the environment and are available to contract through -/// the functions defined on Vec. Values stored in the Vec are transmitted to -/// the environment as [Val]s, and when retrieved from the Vec are -/// transmitted back and converted from [Val] back into their type. -/// -/// The values in a Vec are not guaranteed to be of type `T` and conversion will -/// fail if they are not. Most functions on Vec have a `try_` variation that -/// returns a `Result` that will be `Err` if the conversion fails. Functions -/// that are not prefixed with `try_` will panic if conversion fails. -/// -/// There are some cases where this lack of guarantee is important: -/// -/// - When storing a Vec that has been provided externally as a contract -/// function argument, be aware there is no guarantee that all items in the Vec -/// will be of type `T`. It may be necessary to validate all values, either -/// before storing, or when loading with `try_` variation functions. -/// -/// - When accessing and iterating over a Vec that has been provided externally -/// as a contract function input, and the contract needs to be resilient to -/// failure, use the `try_` variation functions. -/// -/// Functions with an `_unchecked` suffix will panic if called with indexes that -/// are out-of-bounds. -/// -/// To store `u8`s and binary data, use [Bytes]/[BytesN] instead. -/// -/// Vec values can be stored as [Storage], or in other types like [Vec], [Map], -/// etc. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{vec, Env}; -/// -/// let env = Env::default(); -/// let vec = vec![&env, 0, 1, 2, 3]; -/// assert_eq!(vec.len(), 4); -/// ``` -pub struct Vec { - env: Env, - obj: VecObject, - _t: PhantomData, -} - -impl Clone for Vec { - fn clone(&self) -> Self { - Self { - env: self.env.clone(), - obj: self.obj, - _t: self._t, - } - } -} - -impl Eq for Vec where T: IntoVal + TryFromVal {} - -impl PartialEq for Vec -where - T: IntoVal + TryFromVal, -{ - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for Vec -where - T: IntoVal + TryFromVal, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl Ord for Vec -where - T: IntoVal + TryFromVal, -{ - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - #[cfg(not(target_family = "wasm"))] - if !self.env.is_same_env(&other.env) { - return ScVal::from(self).cmp(&ScVal::from(other)); - } - let v = self - .env - .obj_cmp(self.obj.to_val(), other.obj.to_val()) - .unwrap_infallible(); - v.cmp(&0) - } -} - -impl Debug for Vec -where - T: IntoVal + TryFromVal + Debug + Clone, - T::Error: Debug, -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Vec(")?; - let mut iter = self.try_iter(); - if let Some(x) = iter.next() { - write!(f, "{:?}", x)?; - } - for x in iter { - write!(f, ", {:?}", x)?; - } - write!(f, ")")?; - Ok(()) - } -} - -impl TryFromVal> for Vec { - type Error = Infallible; - - fn try_from_val(env: &Env, v: &Vec) -> Result { - Ok(unsafe { Vec::unchecked_new(env.clone(), v.obj) }) - } -} - -// This conflicts with the previous definition unless we add the spurious &, -// which is not .. great. Maybe don't define this particular blanket, or add -// a to_other() method? -impl TryFromVal> for Vec { - type Error = Infallible; - - fn try_from_val(env: &Env, v: &&Vec) -> Result { - Ok(unsafe { Vec::unchecked_new(env.clone(), v.obj) }) - } -} - -impl TryFromVal for Vec -where - T: IntoVal + TryFromVal, -{ - type Error = Infallible; - - #[inline(always)] - fn try_from_val(env: &Env, obj: &VecObject) -> Result { - Ok(unsafe { Vec::::unchecked_new(env.clone(), *obj) }) - } -} - -impl TryFromVal for Vec -where - T: IntoVal + TryFromVal, -{ - type Error = ConversionError; - - #[inline(always)] - fn try_from_val(env: &Env, val: &Val) -> Result { - Ok(VecObject::try_from_val(env, val)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -impl TryFromVal> for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &Vec) -> Result { - Ok(v.to_val()) - } -} - -impl TryFromVal> for Val { - type Error = ConversionError; - - fn try_from_val(_env: &Env, v: &&Vec) -> Result { - Ok(v.to_val()) - } -} - -impl From> for Val -where - T: IntoVal + TryFromVal, -{ - #[inline(always)] - fn from(v: Vec) -> Self { - v.obj.into() - } -} - -impl From> for VecObject -where - T: IntoVal + TryFromVal, -{ - #[inline(always)] - fn from(v: Vec) -> Self { - v.obj - } -} - -#[cfg(not(target_family = "wasm"))] -use super::xdr::{ScVal, ScVec, VecM}; - -#[cfg(not(target_family = "wasm"))] -impl From<&Vec> for ScVal { - fn from(v: &Vec) -> Self { - // This conversion occurs only in test utilities, and theoretically all - // values should convert to an ScVal because the Env won't let the host - // type to exist otherwise, unwrapping. Even if there are edge cases - // that don't, this is a trade off for a better test developer - // experience. - ScVal::try_from_val(&v.env, &v.obj.to_val()).unwrap() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From<&Vec> for ScVec { - fn from(v: &Vec) -> Self { - if let ScVal::Vec(Some(vec)) = ScVal::try_from(v).unwrap() { - vec - } else { - panic!("expected ScVec") - } - } -} - -#[cfg(not(target_family = "wasm"))] -impl From> for VecM { - fn from(v: Vec) -> Self { - ScVec::from(v).0 - } -} - -#[cfg(not(target_family = "wasm"))] -impl From> for ScVal { - fn from(v: Vec) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl From> for ScVec { - fn from(v: Vec) -> Self { - (&v).into() - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Vec -where - T: IntoVal + TryFromVal, -{ - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVal) -> Result { - Ok(VecObject::try_from_val(env, &Val::try_from_val(env, val)?)? - .try_into_val(env) - .unwrap_infallible()) - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal for Vec -where - T: IntoVal + TryFromVal, -{ - type Error = ConversionError; - fn try_from_val(env: &Env, val: &ScVec) -> Result { - ScVal::Vec(Some(val.clone())).try_into_val(env) - } -} - -#[cfg(not(target_family = "wasm"))] -impl TryFromVal> for Vec -where - T: IntoVal + TryFromVal, -{ - type Error = ConversionError; - fn try_from_val(env: &Env, val: &VecM) -> Result { - ScVec(val.clone()).try_into_val(env) - } -} - -impl Vec { - #[inline(always)] - pub(crate) unsafe fn unchecked_new(env: Env, obj: VecObject) -> Self { - Self { - env, - obj, - _t: PhantomData, - } - } - - pub fn env(&self) -> &Env { - &self.env - } - - pub fn as_val(&self) -> &Val { - self.obj.as_val() - } - - pub fn to_val(&self) -> Val { - self.obj.to_val() - } - - pub fn as_object(&self) -> &VecObject { - &self.obj - } - - pub fn to_object(&self) -> VecObject { - self.obj - } - - pub fn to_vals(&self) -> Vec { - unsafe { Vec::::unchecked_new(self.env().clone(), self.obj) } - } -} - -impl Vec -where - T: IntoVal + TryFromVal, -{ - /// Create an empty Vec. - #[inline(always)] - pub fn new(env: &Env) -> Vec { - unsafe { Self::unchecked_new(env.clone(), env.vec_new().unwrap_infallible()) } - } - - /// Create a Vec from the array of items. - #[inline(always)] - pub fn from_array(env: &Env, items: [T; N]) -> Vec { - let mut tmp: [Val; N] = [Val::VOID.to_val(); N]; - for (dst, src) in tmp.iter_mut().zip(items.iter()) { - *dst = src.into_val(env) - } - let vec = env.vec_new_from_slice(&tmp).unwrap_infallible(); - unsafe { Self::unchecked_new(env.clone(), vec) } - } - - /// Create a Vec from an iterator of items. - /// - /// This provides FromIterator-like functionality but requires an Env parameter. - /// - /// Note: This function iteratively adds each item one at a time, making a call to the Soroban - /// environment for each item making it inefficient for joining two [`Vec`]s. Use - /// [`Vec::append`] to join two [`Vec`]s. - /// - /// ### Examples - /// - /// ``` - /// use soroban_sdk::{Env, Vec}; - /// - /// let env = Env::default(); - /// let items = vec![1, 2, 3, 4]; - /// let vec = Vec::from_iter(&env, items.into_iter()); - /// assert_eq!(vec.len(), 4); - /// ``` - #[inline(always)] - pub fn from_iter>(env: &Env, iter: I) -> Vec { - let mut vec = Self::new(env); - vec.extend(iter); - vec - } - - /// Create a Vec from the slice of items. - #[inline(always)] - pub fn from_slice(env: &Env, items: &[T]) -> Vec - where - T: Clone, - { - let mut vec = Vec::new(env); - vec.extend_from_slice(items); - vec - } - - /// Returns the item at the position or None if out-of-bounds. - /// - /// ### Panics - /// - /// If the value at the position cannot be converted to type T. - #[inline(always)] - pub fn get(&self, i: u32) -> Option { - self.try_get(i).unwrap_optimized() - } - - /// Returns the item at the position or None if out-of-bounds. - /// - /// ### Errors - /// - /// If the value at the position cannot be converted to type T. - #[inline(always)] - pub fn try_get(&self, i: u32) -> Result, T::Error> { - if i < self.len() { - self.try_get_unchecked(i).map(|val| Some(val)) - } else { - Ok(None) - } - } - - /// Returns the item at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - /// - /// If the value at the position cannot be converted to type T. - #[inline(always)] - pub fn get_unchecked(&self, i: u32) -> T { - self.try_get_unchecked(i).unwrap_optimized() - } - - /// Returns the item at the position. - /// - /// ### Errors - /// - /// If the value at the position cannot be converted to type T. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn try_get_unchecked(&self, i: u32) -> Result { - let env = self.env(); - let val = env.vec_get(self.obj, i.into()).unwrap_infallible(); - T::try_from_val(env, &val) - } - - /// Sets the item at the position with new value. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn set(&mut self, i: u32, v: T) { - let env = self.env(); - self.obj = env - .vec_put(self.obj, i.into(), v.into_val(env)) - .unwrap_infallible(); - } - - /// Removes the item at the position. - /// - /// Returns `None` if out-of-bounds. - #[inline(always)] - pub fn remove(&mut self, i: u32) -> Option<()> { - if i < self.len() { - self.remove_unchecked(i); - Some(()) - } else { - None - } - } - - /// Removes the item at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn remove_unchecked(&mut self, i: u32) { - let env = self.env(); - self.obj = env.vec_del(self.obj, i.into()).unwrap_infallible(); - } - - /// Adds the item to the front. - /// - /// Increases the length by one, shifts all items up by one, and puts the - /// item in the first position. - #[inline(always)] - pub fn push_front(&mut self, x: T) { - let env = self.env(); - self.obj = env - .vec_push_front(self.obj, x.into_val(env)) - .unwrap_infallible(); - } - - /// Removes and returns the first item or None if empty. - /// - /// ### Panics - /// - /// If the value at the first position cannot be converted to type T. - #[inline(always)] - pub fn pop_front(&mut self) -> Option { - self.try_pop_front().unwrap_optimized() - } - - /// Removes and returns the first item or None if empty. - /// - /// ### Errors - /// - /// If the value at the first position cannot be converted to type T. - #[inline(always)] - pub fn try_pop_front(&mut self) -> Result, T::Error> { - if self.is_empty() { - Ok(None) - } else { - self.try_pop_front_unchecked().map(|val| Some(val)) - } - } - - /// Removes and returns the first item. - /// - /// ### Panics - /// - /// If the vec is empty. - /// - /// If the value at the first position cannot be converted to type T. - #[inline(always)] - pub fn pop_front_unchecked(&mut self) -> T { - self.try_pop_front_unchecked().unwrap_optimized() - } - - /// Removes and returns the first item. - /// - /// ### Errors - /// - /// If the value at the first position cannot be converted to type T. - /// - /// ### Panics - /// - /// If the vec is empty. - #[inline(always)] - pub fn try_pop_front_unchecked(&mut self) -> Result { - let last = self.try_first_unchecked()?; - let env = self.env(); - self.obj = env.vec_pop_front(self.obj).unwrap_infallible(); - Ok(last) - } - - /// Adds the item to the back. - /// - /// Increases the length by one and puts the item in the last position. - #[inline(always)] - pub fn push_back(&mut self, x: T) { - let env = self.env(); - self.obj = env - .vec_push_back(self.obj, x.into_val(env)) - .unwrap_infallible(); - } - - /// Removes and returns the last item or None if empty. - /// - /// ### Panics - /// - /// If the value at the last position cannot be converted to type T. - #[inline(always)] - pub fn pop_back(&mut self) -> Option { - self.try_pop_back().unwrap_optimized() - } - - /// Removes and returns the last item or None if empty. - /// - /// ### Errors - /// - /// If the value at the last position cannot be converted to type T. - #[inline(always)] - pub fn try_pop_back(&mut self) -> Result, T::Error> { - if self.is_empty() { - Ok(None) - } else { - self.try_pop_back_unchecked().map(|val| Some(val)) - } - } - - /// Removes and returns the last item. - /// - /// ### Panics - /// - /// If the vec is empty. - /// - /// If the value at the last position cannot be converted to type T. - #[inline(always)] - pub fn pop_back_unchecked(&mut self) -> T { - self.try_pop_back_unchecked().unwrap_optimized() - } - - /// Removes and returns the last item. - /// - /// ### Errors - /// - /// If the value at the last position cannot be converted to type T. - /// - /// ### Panics - /// - /// If the vec is empty. - #[inline(always)] - pub fn try_pop_back_unchecked(&mut self) -> Result { - let last = self.try_last_unchecked()?; - let env = self.env(); - self.obj = env.vec_pop_back(self.obj).unwrap_infallible(); - Ok(last) - } - - /// Returns the first item or None if empty. - /// - /// ### Panics - /// - /// If the value at the first position cannot be converted to type T. - #[inline(always)] - pub fn first(&self) -> Option { - self.try_first().unwrap_optimized() - } - - /// Returns the first item or None if empty. - /// - /// ### Errors - /// - /// If the value at the first position cannot be converted to type T. - #[inline(always)] - pub fn try_first(&self) -> Result, T::Error> { - if self.is_empty() { - Ok(None) - } else { - self.try_first_unchecked().map(|val| Some(val)) - } - } - - /// Returns the first item. - /// - /// ### Panics - /// - /// If the vec is empty. - /// - /// If the value at the first position cannot be converted to type T. - #[inline(always)] - pub fn first_unchecked(&self) -> T { - self.try_first_unchecked().unwrap_optimized() - } - - /// Returns the first item. - /// - /// ### Errors - /// - /// If the value at the first position cannot be converted to type T. - /// - /// ### Panics - /// - /// If the vec is empty. - #[inline(always)] - pub fn try_first_unchecked(&self) -> Result { - let env = &self.env; - let val = env.vec_front(self.obj).unwrap_infallible(); - T::try_from_val(env, &val) - } - - /// Returns the last item or None if empty. - /// - /// ### Panics - /// - /// If the value at the last position cannot be converted to type T. - #[inline(always)] - pub fn last(&self) -> Option { - self.try_last().unwrap_optimized() - } - - /// Returns the last item or None if empty. - /// - /// ### Errors - /// - /// If the value at the last position cannot be converted to type T. - #[inline(always)] - pub fn try_last(&self) -> Result, T::Error> { - if self.is_empty() { - Ok(None) - } else { - self.try_last_unchecked().map(|val| Some(val)) - } - } - - /// Returns the last item. - /// - /// ### Panics - /// - /// If the vec is empty. - /// - /// If the value at the last position cannot be converted to type T. - #[inline(always)] - pub fn last_unchecked(&self) -> T { - self.try_last_unchecked().unwrap_optimized() - } - - /// Returns the last item. - /// - /// ### Errors - /// - /// If the value at the last position cannot be converted to type T. - /// - /// ### Panics - /// - /// If the vec is empty. - #[inline(always)] - pub fn try_last_unchecked(&self) -> Result { - let env = self.env(); - let val = env.vec_back(self.obj).unwrap_infallible(); - T::try_from_val(env, &val) - } - - /// Inserts an item at the position. - /// - /// ### Panics - /// - /// If the position is out-of-bounds. - #[inline(always)] - pub fn insert(&mut self, i: u32, x: T) { - let env = self.env(); - self.obj = env - .vec_insert(self.obj, i.into(), x.into_val(env)) - .unwrap_infallible(); - } - - /// Append the items. - #[inline(always)] - pub fn append(&mut self, other: &Vec) { - let env = self.env(); - self.obj = env.vec_append(self.obj, other.obj).unwrap_infallible(); - } - - /// Extend with the items in the array. - #[inline(always)] - pub fn extend_from_array(&mut self, items: [T; N]) { - self.append(&Self::from_array(&self.env, items)) - } - - /// Extend with the items in the slice. - #[inline(always)] - pub fn extend_from_slice(&mut self, items: &[T]) - where - T: Clone, - { - for item in items { - self.push_back(item.clone()); - } - } -} - -impl Vec { - /// Returns a subset of the bytes as defined by the start and end bounds of - /// the range. - /// - /// ### Panics - /// - /// If the range is out-of-bounds. - #[must_use] - pub fn slice(&self, r: impl RangeBounds) -> Self { - let start_bound = match r.start_bound() { - Bound::Included(s) => *s, - Bound::Excluded(s) => s - .checked_add(1) - .expect_optimized("attempt to add with overflow"), - Bound::Unbounded => 0, - }; - let end_bound = match r.end_bound() { - Bound::Included(s) => s - .checked_add(1) - .expect_optimized("attempt to add with overflow"), - Bound::Excluded(s) => *s, - Bound::Unbounded => self.len(), - }; - let env = self.env(); - let obj = env - .vec_slice(self.obj, start_bound.into(), end_bound.into()) - .unwrap_infallible(); - unsafe { Self::unchecked_new(env.clone(), obj) } - } - - /// Returns copy of the vec shuffled using the NOT-SECURE PRNG. - /// - /// In tests, must be called from within a running contract. - /// - /// # Warning - /// - /// **The pseudo-random generator used to perform the shuffle is not - /// suitable for security-sensitive work.** - pub fn shuffle(&mut self) { - let env = self.env(); - env.prng().shuffle(self); - } - - /// Returns copy of the vec shuffled using the NOT-SECURE PRNG. - /// - /// In tests, must be called from within a running contract. - /// - /// # Warning - /// - /// **The pseudo-random generator used to perform the shuffle is not - /// suitable for security-sensitive work.** - #[must_use] - pub fn to_shuffled(&self) -> Self { - let mut copy = self.clone(); - copy.shuffle(); - copy - } - - /// Returns true if the vec is empty and contains no items. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the number of items in the vec. - #[inline(always)] - pub fn len(&self) -> u32 { - self.env.vec_len(self.obj).unwrap_infallible().into() - } -} - -impl Vec -where - T: IntoVal, -{ - /// Returns true if the Vec contains the item. - #[inline(always)] - pub fn contains(&self, item: impl Borrow) -> bool { - let env = self.env(); - let val = item.borrow().into_val(env); - !env.vec_first_index_of(self.obj, val) - .unwrap_infallible() - .is_void() - } - - /// Returns the index of the first occurrence of the item. - /// - /// If the item cannot be found [None] is returned. - #[inline(always)] - pub fn first_index_of(&self, item: impl Borrow) -> Option { - let env = self.env(); - let val = item.borrow().into_val(env); - env.vec_first_index_of(self.obj, val) - .unwrap_infallible() - .try_into_val(env) - .unwrap() - } - - /// Returns the index of the last occurrence of the item. - /// - /// If the item cannot be found [None] is returned. - #[inline(always)] - pub fn last_index_of(&self, item: impl Borrow) -> Option { - let env = self.env(); - let val = item.borrow().into_val(env); - env.vec_last_index_of(self.obj, val) - .unwrap_infallible() - .try_into_val(env) - .unwrap() - } - - /// Returns the index of an occurrence of the item in an already sorted - /// [Vec], or the index of where the item can be inserted to keep the [Vec] - /// sorted. - /// - /// If the item is found, [Result::Ok] is returned containing the index of - /// the item. - /// - /// If the item is not found, [Result::Err] is returned containing the index - /// of where the item could be inserted to retain the sorted ordering. - #[inline(always)] - pub fn binary_search(&self, item: impl Borrow) -> Result { - let env = self.env(); - let val = item.borrow().into_val(env); - let high_low = env.vec_binary_search(self.obj, val).unwrap_infallible(); - let high: u32 = (high_low >> u32::BITS) as u32; - let low: u32 = high_low as u32; - if high == 1 { - Ok(low) - } else { - Err(low) - } - } -} - -impl Vec> -where - T: IntoVal + TryFromVal, - T: Clone, -{ - #[inline(always)] - pub fn concat(&self) -> Vec { - let mut concatenated = vec![self.env()]; - for vec in self.iter() { - concatenated.append(&vec); - } - concatenated - } -} - -impl IntoIterator for Vec -where - T: IntoVal + TryFromVal, -{ - type Item = T; - type IntoIter = UnwrappedIter, T, T::Error>; - - fn into_iter(self) -> Self::IntoIter { - VecTryIter::new(self).unwrapped() - } -} - -impl IntoIterator for &Vec -where - T: IntoVal + TryFromVal, -{ - type Item = T; - type IntoIter = UnwrappedIter, T, T::Error>; - - fn into_iter(self) -> Self::IntoIter { - self.clone().into_iter() - } -} - -impl Extend for Vec -where - T: IntoVal + TryFromVal, -{ - fn extend>(&mut self, iter: I) { - for item in iter { - self.push_back(item); - } - } -} - -impl Vec -where - T: IntoVal + TryFromVal, -{ - /// Returns an iterator over the elements of the vec. - /// - /// Each element is converted from [Val] to `T` as it is yielded. - /// - /// ### Panics - /// - /// If any element cannot be converted to type `T`. Use - /// [`try_iter`](Vec::try_iter) to handle conversion errors. - #[inline(always)] - pub fn iter(&self) -> UnwrappedIter, T, T::Error> - where - T: IntoVal + TryFromVal + Clone, - T::Error: Debug, - { - self.try_iter().unwrapped() - } - - /// Returns an iterator over the elements of the vec, yielding - /// `Result` for each element. - #[inline(always)] - pub fn try_iter(&self) -> VecTryIter - where - T: IntoVal + TryFromVal + Clone, - { - VecTryIter::new(self.clone()) - } - - #[inline(always)] - pub fn into_try_iter(self) -> VecTryIter - where - T: IntoVal + TryFromVal + Clone, - T::Error: Debug, - { - VecTryIter::new(self) - } -} - -#[derive(Clone)] -pub struct VecTryIter { - vec: Vec, - start: u32, // inclusive - end: u32, // exclusive -} - -impl VecTryIter { - fn new(vec: Vec) -> Self { - Self { - start: 0, - end: vec.len(), - vec, - } - } - - fn into_vec(self) -> Vec { - self.vec.slice(self.start..self.end) - } -} - -impl Iterator for VecTryIter -where - T: IntoVal + TryFromVal, -{ - type Item = Result; - - fn next(&mut self) -> Option { - if self.start < self.end { - let val = self.vec.try_get_unchecked(self.start); - self.start += 1; - Some(val) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = (self.end - self.start) as usize; - (len, Some(len)) - } - - // TODO: Implement other functions as optimizations since the iterator is - // backed by an indexable collection. -} - -impl DoubleEndedIterator for VecTryIter -where - T: IntoVal + TryFromVal, -{ - fn next_back(&mut self) -> Option { - if self.start < self.end { - let val = self.vec.try_get_unchecked(self.end - 1); - self.end -= 1; - Some(val) - } else { - None - } - } - - // TODO: Implement other functions as optimizations since the iterator is - // backed by an indexable collection. -} - -impl FusedIterator for VecTryIter where T: IntoVal + TryFromVal {} - -impl ExactSizeIterator for VecTryIter -where - T: IntoVal + TryFromVal, -{ - fn len(&self) -> usize { - (self.end - self.start) as usize - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_vec_macro() { - let env = Env::default(); - assert_eq!(vec![&env], Vec::::new(&env)); - assert_eq!(vec![&env,], Vec::::new(&env)); - assert_eq!(vec![&env, 1], { - let mut v = Vec::new(&env); - v.push_back(1); - v - }); - assert_eq!(vec![&env, 1,], { - let mut v = Vec::new(&env); - v.push_back(1); - v - }); - assert_eq!(vec![&env, 3, 2, 1,], { - let mut v = Vec::new(&env); - v.push_back(3); - v.push_back(2); - v.push_back(1); - v - }); - } - - #[test] - fn test_vec_to_val() { - let env = Env::default(); - - let vec = Vec::::from_slice(&env, &[0, 1, 2, 3]); - let val: Val = vec.clone().into_val(&env); - let rt: Vec = val.into_val(&env); - - assert_eq!(vec, rt); - } - - #[test] - fn test_ref_vec_to_val() { - let env = Env::default(); - - let vec = Vec::::from_slice(&env, &[0, 1, 2, 3]); - let val: Val = (&vec).into_val(&env); - let rt: Vec = val.into_val(&env); - - assert_eq!(vec, rt); - } - - #[test] - fn test_double_ref_vec_to_val() { - let env = Env::default(); - - let vec = Vec::::from_slice(&env, &[0, 1, 2, 3]); - let val: Val = (&&vec).into_val(&env); - let rt: Vec = val.into_val(&env); - - assert_eq!(vec, rt); - } - - #[test] - fn test_vec_raw_val_type() { - let env = Env::default(); - - let mut vec = Vec::::new(&env); - assert_eq!(vec.len(), 0); - vec.push_back(10); - assert_eq!(vec.len(), 1); - vec.push_back(20); - assert_eq!(vec.len(), 2); - vec.push_back(30); - assert_eq!(vec.len(), 3); - - let vec_ref = &vec; - assert_eq!(vec_ref.len(), 3); - - let mut vec_copy = vec.clone(); - assert!(vec == vec_copy); - assert_eq!(vec_copy.len(), 3); - vec_copy.push_back(40); - assert_eq!(vec_copy.len(), 4); - assert!(vec != vec_copy); - - assert_eq!(vec.len(), 3); - assert_eq!(vec_ref.len(), 3); - - _ = vec_copy.pop_back_unchecked(); - assert!(vec == vec_copy); - } - - #[test] - fn test_vec_env_val_type() { - let env = Env::default(); - - let mut vec = Vec::::new(&env); - assert_eq!(vec.len(), 0); - vec.push_back(-10); - assert_eq!(vec.len(), 1); - vec.push_back(20); - assert_eq!(vec.len(), 2); - vec.push_back(-30); - assert_eq!(vec.len(), 3); - - let vec_ref = &vec; - assert_eq!(vec_ref.len(), 3); - - let mut vec_copy = vec.clone(); - assert!(vec == vec_copy); - assert_eq!(vec_copy.len(), 3); - vec_copy.push_back(40); - assert_eq!(vec_copy.len(), 4); - assert!(vec != vec_copy); - - assert_eq!(vec.len(), 3); - assert_eq!(vec_ref.len(), 3); - - _ = vec_copy.pop_back_unchecked(); - assert!(vec == vec_copy); - } - - #[test] - fn test_vec_to_vals() { - let env = Env::default(); - let vec = vec![&env, 0, 1, 2, 3, 4]; - let vals = vec.to_vals(); - assert_eq!( - vals, - vec![ - &env, - Val::from_i32(0).to_val(), - Val::from_i32(1).to_val(), - Val::from_i32(2).to_val(), - Val::from_i32(3).to_val(), - Val::from_i32(4).to_val(), - ] - ); - } - - #[test] - fn test_vec_recursive() { - let env = Env::default(); - - let mut vec_inner = Vec::::new(&env); - vec_inner.push_back(-10); - assert_eq!(vec_inner.len(), 1); - - let mut vec_outer = Vec::>::new(&env); - vec_outer.push_back(vec_inner); - assert_eq!(vec_outer.len(), 1); - } - - #[test] - fn test_vec_concat() { - let env = Env::default(); - let vec_1: Vec = vec![&env, 1, 2, 3]; - let vec_2: Vec = vec![&env, 4, 5, 6]; - let vec = vec![&env, vec_1, vec_2].concat(); - assert_eq!(vec, vec![&env, 1, 2, 3, 4, 5, 6]); - } - - #[test] - fn test_vec_slice() { - let env = Env::default(); - - let vec = vec![&env, 0, 1, 2, 3, 4]; - assert_eq!(vec.len(), 5); - - let slice = vec.slice(..); - assert_eq!(slice, vec![&env, 0, 1, 2, 3, 4]); - - let slice = vec.slice(0..5); - assert_eq!(slice, vec![&env, 0, 1, 2, 3, 4]); - - let slice = vec.slice(0..=4); - assert_eq!(slice, vec![&env, 0, 1, 2, 3, 4]); - - let slice = vec.slice(1..); - assert_eq!(slice, vec![&env, 1, 2, 3, 4]); - - let slice = vec.slice(..4); - assert_eq!(slice, vec![&env, 0, 1, 2, 3]); - - let slice = vec.slice(..=3); - assert_eq!(slice, vec![&env, 0, 1, 2, 3]); - - let slice = vec.slice(1..4); - assert_eq!(slice, vec![&env, 1, 2, 3]); - - let slice = vec.slice(1..=3); - assert_eq!(slice, vec![&env, 1, 2, 3]); - - // An exclusive start is technically possible due to the lack of - // constraints in the RangeBounds trait, however this is unlikely to - // happen since no syntax shorthand exists for it. - let slice = vec.slice((Bound::Excluded(0), Bound::Included(3))); - assert_eq!(slice, vec![&env, 1, 2, 3]); - let slice = vec.slice((Bound::Excluded(0), Bound::Excluded(3))); - assert_eq!(slice, vec![&env, 1, 2]); - } - - #[test] - fn test_vec_iter() { - let env = Env::default(); - - let vec: Vec<()> = vec![&env]; - let mut iter = vec.iter(); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let vec = vec![&env, 0, 1, 2, 3, 4]; - - let mut iter = vec.iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut iter = vec.iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(0)); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next_back(), Some(4)); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next_back(), Some(3)); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - - let mut iter = vec.iter().rev(); - assert_eq!(iter.next(), Some(4)); - assert_eq!(iter.next_back(), Some(0)); - assert_eq!(iter.next_back(), Some(1)); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_vec_iter_panic_on_conversion() { - let env = Env::default(); - - let vec: Val = (1i32,).try_into_val(&env).unwrap(); - let vec: Vec = vec.try_into_val(&env).unwrap(); - - let mut iter = vec.iter(); - iter.next(); - } - - #[test] - fn test_vec_try_iter() { - let env = Env::default(); - - let vec: Vec<()> = vec![&env]; - let mut iter = vec.try_iter(); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let vec = vec![&env, 0, 1, 2, 3, 4]; - - let mut iter = vec.try_iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(Ok(0))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next(), Some(Ok(1))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next(), Some(Ok(2))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(Ok(3))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(Ok(4))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - - let mut iter = vec.try_iter(); - assert_eq!(iter.len(), 5); - assert_eq!(iter.next(), Some(Ok(0))); - assert_eq!(iter.len(), 4); - assert_eq!(iter.next_back(), Some(Ok(4))); - assert_eq!(iter.len(), 3); - assert_eq!(iter.next_back(), Some(Ok(3))); - assert_eq!(iter.len(), 2); - assert_eq!(iter.next(), Some(Ok(1))); - assert_eq!(iter.len(), 1); - assert_eq!(iter.next(), Some(Ok(2))); - assert_eq!(iter.len(), 0); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - - let mut iter = vec.try_iter().rev(); - assert_eq!(iter.next(), Some(Ok(4))); - assert_eq!(iter.next_back(), Some(Ok(0))); - assert_eq!(iter.next_back(), Some(Ok(1))); - assert_eq!(iter.next(), Some(Ok(3))); - assert_eq!(iter.next(), Some(Ok(2))); - assert_eq!(iter.next(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next_back(), None); - } - - #[test] - fn test_vec_try_iter_error_on_conversion() { - let env = Env::default(); - - let vec: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let vec: Vec = vec.try_into_val(&env).unwrap(); - - let mut iter = vec.try_iter(); - assert_eq!(iter.next(), Some(Ok(1))); - assert_eq!(iter.next(), Some(Err(ConversionError.into()))); - } - - #[test] - fn test_vec_iter_into_vec() { - let env = Env::default(); - - let vec = vec![&env, 0, 1, 2, 3, 4]; - - let mut iter = vec.try_iter(); - assert_eq!(iter.next(), Some(Ok(0))); - assert_eq!(iter.next(), Some(Ok(1))); - assert_eq!(iter.into_vec(), vec![&env, 2, 3, 4]); - } - - #[test] - fn test_contains() { - let env = Env::default(); - let vec = vec![&env, 0, 3, 5, 7, 9, 5]; - assert_eq!(vec.contains(&2), false); - assert_eq!(vec.contains(2), false); - assert_eq!(vec.contains(&3), true); - assert_eq!(vec.contains(3), true); - assert_eq!(vec.contains(&5), true); - assert_eq!(vec.contains(5), true); - } - - #[test] - fn test_first_index_of() { - let env = Env::default(); - - let vec = vec![&env, 0, 3, 5, 7, 9, 5]; - assert_eq!(vec.first_index_of(&2), None); - assert_eq!(vec.first_index_of(2), None); - assert_eq!(vec.first_index_of(&3), Some(1)); - assert_eq!(vec.first_index_of(3), Some(1)); - assert_eq!(vec.first_index_of(&5), Some(2)); - assert_eq!(vec.first_index_of(5), Some(2)); - } - - #[test] - fn test_last_index_of() { - let env = Env::default(); - - let vec = vec![&env, 0, 3, 5, 7, 9, 5]; - assert_eq!(vec.last_index_of(&2), None); - assert_eq!(vec.last_index_of(2), None); - assert_eq!(vec.last_index_of(&3), Some(1)); - assert_eq!(vec.last_index_of(3), Some(1)); - assert_eq!(vec.last_index_of(&5), Some(5)); - assert_eq!(vec.last_index_of(5), Some(5)); - } - - #[test] - fn test_binary_search() { - let env = Env::default(); - - let vec = vec![&env, 0, 3, 5, 5, 7, 9]; - assert_eq!(vec.binary_search(&2), Err(1)); - assert_eq!(vec.binary_search(2), Err(1)); - assert_eq!(vec.binary_search(&3), Ok(1)); - assert_eq!(vec.binary_search(3), Ok(1)); - assert_eq!(vec.binary_search(&5), Ok(3)); - assert_eq!(vec.binary_search(5), Ok(3)); - } - - #[cfg(not(target_family = "wasm"))] - #[test] - fn test_scval_accessibility_from_udt_types() { - use crate::TryFromVal; - let env = Env::default(); - let v = vec![&env, 1]; - let val: ScVal = v.clone().try_into().unwrap(); - let roundtrip = Vec::::try_from_val(&env, &val).unwrap(); - assert_eq!(v, roundtrip); - } - - #[test] - fn test_insert_and_set() { - let env = Env::default(); - let mut v = Vec::::new(&env); - v.insert(0, 3); - v.insert(0, 1); - v.insert(1, 4); - v.insert(3, 6); - assert_eq!(v, vec![&env, 1, 4, 3, 6]); - v.set(0, 7); - v.set(1, 6); - v.set(2, 2); - v.set(3, 5); - assert_eq!(v, vec![&env, 7, 6, 2, 5]); - } - - #[test] - fn test_is_empty_and_len() { - let env = Env::default(); - - let mut v: Vec = vec![&env, 1, 4, 3]; - assert_eq!(v.is_empty(), false); - assert_eq!(v.len(), 3); - - v = vec![&env]; - assert_eq!(v.is_empty(), true); - assert_eq!(v.len(), 0); - } - - #[test] - fn test_push_pop_front() { - let env = Env::default(); - - let mut v = Vec::::new(&env); - v.push_front(42); - assert_eq!(v, vec![&env, 42]); - v.push_front(1); - assert_eq!(v, vec![&env, 1, 42]); - v.push_front(5); - assert_eq!(v, vec![&env, 5, 1, 42]); - v.push_front(7); - assert_eq!(v, vec![&env, 7, 5, 1, 42]); - - let popped = v.pop_front(); - assert_eq!(popped, Some(7)); - assert_eq!(v, vec![&env, 5, 1, 42]); - - let popped = v.try_pop_front(); - assert_eq!(popped, Ok(Some(5))); - assert_eq!(v, vec![&env, 1, 42]); - - let popped = v.pop_front_unchecked(); - assert_eq!(popped, 1); - assert_eq!(v, vec![&env, 42]); - - let popped = v.try_pop_front_unchecked(); - assert_eq!(popped, Ok(42)); - assert_eq!(v, vec![&env]); - - assert_eq!(v.pop_front(), None); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_pop_front_panics_on_conversion() { - let env = Env::default(); - - let v: Val = (1i32,).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - v.pop_front(); - } - - #[test] - fn test_try_pop_front_errors_on_conversion() { - let env = Env::default(); - - let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - assert_eq!(v.try_pop_front(), Ok(Some(1))); - assert_eq!(v.try_pop_front(), Err(ConversionError.into())); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_pop_front_unchecked_panics_on_conversion() { - let env = Env::default(); - - let v: Val = (1i32,).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - v.pop_front_unchecked(); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_pop_front_unchecked_panics_on_out_of_bounds() { - let env = Env::default(); - - let mut v = Vec::::new(&env); - - v.pop_front_unchecked(); - } - - #[test] - fn test_try_pop_front_unchecked_errors_on_conversion() { - let env = Env::default(); - - let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - assert_eq!(v.try_pop_front_unchecked(), Ok(1)); - assert_eq!(v.try_pop_front_unchecked(), Err(ConversionError.into())); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_try_pop_front_unchecked_panics_on_out_of_bounds() { - let env = Env::default(); - - let mut v = Vec::::new(&env); - - let _ = v.try_pop_front_unchecked(); - } - - #[test] - fn test_push_pop_back() { - let env = Env::default(); - - let mut v = Vec::::new(&env); - v.push_back(42); - assert_eq!(v, vec![&env, 42]); - v.push_back(1); - assert_eq!(v, vec![&env, 42, 1]); - v.push_back(5); - assert_eq!(v, vec![&env, 42, 1, 5]); - v.push_back(7); - assert_eq!(v, vec![&env, 42, 1, 5, 7]); - - let popped = v.pop_back(); - assert_eq!(popped, Some(7)); - assert_eq!(v, vec![&env, 42, 1, 5]); - - let popped = v.try_pop_back(); - assert_eq!(popped, Ok(Some(5))); - assert_eq!(v, vec![&env, 42, 1]); - - let popped = v.pop_back_unchecked(); - assert_eq!(popped, 1); - assert_eq!(v, vec![&env, 42]); - - let popped = v.try_pop_back_unchecked(); - assert_eq!(popped, Ok(42)); - assert_eq!(v, vec![&env]); - - assert_eq!(v.pop_back(), None); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_pop_back_panics_on_conversion() { - let env = Env::default(); - - let v: Val = (1i32,).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - v.pop_back(); - } - - #[test] - fn test_try_pop_back_errors_on_conversion() { - let env = Env::default(); - - let v: Val = (1i32, 2i64).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - assert_eq!(v.try_pop_back(), Ok(Some(2))); - assert_eq!(v.try_pop_back(), Err(ConversionError.into())); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_pop_back_unchecked_panics_on_conversion() { - let env = Env::default(); - - let v: Val = (1i32,).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - v.pop_back_unchecked(); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_pop_back_unchecked_panics_on_out_of_bounds() { - let env = Env::default(); - - let mut v = Vec::::new(&env); - - v.pop_back_unchecked(); - } - - #[test] - fn test_try_pop_back_unchecked_errors_on_conversion() { - let env = Env::default(); - - let v: Val = (1i32, 2i64).try_into_val(&env).unwrap(); - let mut v: Vec = v.try_into_val(&env).unwrap(); - - assert_eq!(v.try_pop_back_unchecked(), Ok(2)); - assert_eq!(v.try_pop_back_unchecked(), Err(ConversionError.into())); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_try_pop_back_unchecked_panics_on_out_of_bounds() { - let env = Env::default(); - - let mut v = Vec::::new(&env); - - let _ = v.try_pop_back_unchecked(); - } - - #[test] - fn test_get() { - let env = Env::default(); - - let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - - // get each item - assert_eq!(v.get(3), Some(5)); - assert_eq!(v.get(0), Some(0)); - assert_eq!(v.get(1), Some(3)); - assert_eq!(v.get(2), Some(5)); - assert_eq!(v.get(5), Some(9)); - assert_eq!(v.get(4), Some(7)); - - assert_eq!(v.get(v.len()), None); - assert_eq!(v.get(v.len() + 1), None); - assert_eq!(v.get(u32::MAX), None); - - // tests on an empty vec - let v = Vec::::new(&env); - assert_eq!(v.get(0), None); - assert_eq!(v.get(v.len()), None); - assert_eq!(v.get(v.len() + 1), None); - assert_eq!(v.get(u32::MAX), None); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_get_panics_on_conversion() { - let env = Env::default(); - - let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let v: Vec = v.try_into_val(&env).unwrap(); - - // panic because element one is not of the expected type - assert_eq!(v.get(1), Some(5)); - } - - #[test] - fn test_try_get() { - let env = Env::default(); - - let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - - // get each item - assert_eq!(v.try_get(3), Ok(Some(5))); - assert_eq!(v.try_get(0), Ok(Some(0))); - assert_eq!(v.try_get(1), Ok(Some(3))); - assert_eq!(v.try_get(2), Ok(Some(5))); - assert_eq!(v.try_get(5), Ok(Some(9))); - assert_eq!(v.try_get(4), Ok(Some(7))); - - assert_eq!(v.try_get(v.len()), Ok(None)); - assert_eq!(v.try_get(v.len() + 1), Ok(None)); - assert_eq!(v.try_get(u32::MAX), Ok(None)); - - // tests on an empty vec - let v = Vec::::new(&env); - assert_eq!(v.try_get(0), Ok(None)); - assert_eq!(v.try_get(v.len()), Ok(None)); - assert_eq!(v.try_get(v.len() + 1), Ok(None)); - assert_eq!(v.try_get(u32::MAX), Ok(None)); - - // errors - let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let v: Vec = v.try_into_val(&env).unwrap(); - assert_eq!(v.try_get(0), Ok(Some(1))); - assert_eq!(v.try_get(1), Err(ConversionError.into())); - } - - #[test] - fn test_get_unchecked() { - let env = Env::default(); - - let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - - // get each item - assert_eq!(v.get_unchecked(3), 5); - assert_eq!(v.get_unchecked(0), 0); - assert_eq!(v.get_unchecked(1), 3); - assert_eq!(v.get_unchecked(2), 5); - assert_eq!(v.get_unchecked(5), 9); - assert_eq!(v.get_unchecked(4), 7); - } - - #[test] - #[should_panic(expected = "Error(Value, UnexpectedType)")] - fn test_get_unchecked_panics_on_conversion() { - let env = Env::default(); - - let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let v: Vec = v.try_into_val(&env).unwrap(); - - // panic because element one is not of the expected type - v.get_unchecked(1); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_get_unchecked_panics_on_out_of_bounds() { - let env = Env::default(); - - let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - _ = v.get_unchecked(v.len()); // out of bound get - } - - #[test] - fn test_try_get_unchecked() { - let env = Env::default(); - - let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - - // get each item - assert_eq!(v.try_get_unchecked(3), Ok(5)); - assert_eq!(v.try_get_unchecked(0), Ok(0)); - assert_eq!(v.try_get_unchecked(1), Ok(3)); - assert_eq!(v.try_get_unchecked(2), Ok(5)); - assert_eq!(v.try_get_unchecked(5), Ok(9)); - assert_eq!(v.try_get_unchecked(4), Ok(7)); - - // errors - let v: Val = (1i64, 2i32).try_into_val(&env).unwrap(); - let v: Vec = v.try_into_val(&env).unwrap(); - assert_eq!(v.try_get_unchecked(0), Ok(1)); - assert_eq!(v.try_get_unchecked(1), Err(ConversionError.into())); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_try_get_unchecked_panics() { - let env = Env::default(); - - let v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - _ = v.try_get_unchecked(v.len()); // out of bound get - } - - #[test] - fn test_remove() { - let env = Env::default(); - let mut v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - - assert_eq!(v.remove(0), Some(())); - assert_eq!(v.remove(2), Some(())); - assert_eq!(v.remove(3), Some(())); - - assert_eq!(v, vec![&env, 3, 5, 7]); - assert_eq!(v.len(), 3); - - // out of bound removes - assert_eq!(v.remove(v.len()), None); - assert_eq!(v.remove(v.len() + 1), None); - assert_eq!(v.remove(u32::MAX), None); - - // remove rest of items - assert_eq!(v.remove(0), Some(())); - assert_eq!(v.remove(0), Some(())); - assert_eq!(v.remove(0), Some(())); - assert_eq!(v, vec![&env]); - assert_eq!(v.len(), 0); - - // try remove from empty vec - assert_eq!(v.remove(0), None); - assert_eq!(v.remove(v.len()), None); - assert_eq!(v.remove(v.len() + 1), None); - assert_eq!(v.remove(u32::MAX), None); - } - - #[test] - fn test_remove_unchecked() { - let env = Env::default(); - let mut v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - - assert_eq!(v.remove_unchecked(0), ()); - assert_eq!(v.remove_unchecked(2), ()); - assert_eq!(v.remove_unchecked(3), ()); - - assert_eq!(v, vec![&env, 3, 5, 7]); - assert_eq!(v.len(), 3); - - // remove rest of items - assert_eq!(v.remove_unchecked(0), ()); - assert_eq!(v.remove_unchecked(0), ()); - assert_eq!(v.remove_unchecked(0), ()); - assert_eq!(v, vec![&env]); - assert_eq!(v.len(), 0); - } - - #[test] - #[should_panic(expected = "HostError: Error(Object, IndexBounds)")] - fn test_remove_unchecked_panics() { - let env = Env::default(); - let mut v: Vec = vec![&env, 0, 3, 5, 5, 7, 9]; - v.remove_unchecked(v.len()) - } - - #[test] - fn test_extend() { - let env = Env::default(); - let mut v: Vec = vec![&env, 1, 2, 3]; - - // Extend with a std vector - let items = std::vec![4, 5, 6]; - v.extend(items); - assert_eq!(v, vec![&env, 1, 2, 3, 4, 5, 6]); - assert_eq!(v.len(), 6); - - // Extend with an array - v.extend([7, 8, 9]); - assert_eq!(v, vec![&env, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - assert_eq!(v.len(), 9); - - // Extend with an empty iterator - let empty: std::vec::Vec = std::vec::Vec::new(); - v.extend(empty); - assert_eq!(v, vec![&env, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - assert_eq!(v.len(), 9); - } - - #[test] - fn test_extend_empty_vec() { - let env = Env::default(); - let mut v: Vec = vec![&env]; - - // Extend empty vec with items - v.extend([1, 2, 3, 4, 5]); - assert_eq!(v, vec![&env, 1, 2, 3, 4, 5]); - assert_eq!(v.len(), 5); - } - - #[test] - fn test_from_iter() { - let env = Env::default(); - - // Create from std vector iterator - let items = std::vec![1, 2, 3, 4, 5]; - let v = Vec::from_iter(&env, items); - assert_eq!(v, vec![&env, 1, 2, 3, 4, 5]); - assert_eq!(v.len(), 5); - - // Create from array iterator - let v2 = Vec::from_iter(&env, [10, 20, 30]); - assert_eq!(v2, vec![&env, 10, 20, 30]); - assert_eq!(v2.len(), 3); - - // Create from range - let v3 = Vec::from_iter(&env, 1..=4); - assert_eq!(v3, vec![&env, 1, 2, 3, 4]); - assert_eq!(v3.len(), 4); - } - - #[test] - fn test_from_iter_empty() { - let env = Env::default(); - - // Create from empty iterator - let empty: std::vec::Vec = std::vec::Vec::new(); - let v = Vec::from_iter(&env, empty); - assert_eq!(v, vec![&env]); - assert_eq!(v.len(), 0); - - // Create from empty range - let v2 = Vec::from_iter(&env, 1..1); - assert_eq!(v2, vec![&env]); - assert_eq!(v2.len(), 0); - } - - #[test] - fn test_from_iter_different_types() { - let env = Env::default(); - - // Test with strings - let strings = std::vec!["hello".to_string(), "world".to_string(), "test".to_string()]; - let v = Vec::from_iter(&env, strings); - assert_eq!( - v, - vec![ - &env, - "hello".to_string(), - "world".to_string(), - "test".to_string() - ] - ); - assert_eq!(v.len(), 3); - - // Test with booleans - let bools = [true, false, true, false]; - let v2 = Vec::from_iter(&env, bools.into_iter()); - assert_eq!(v2, vec![&env, true, false, true, false]); - assert_eq!(v2.len(), 4); - } -} diff --git a/temp_sdk/soroban-sdk-26.0.1/src/xdr.rs b/temp_sdk/soroban-sdk-26.0.1/src/xdr.rs deleted file mode 100644 index 5458815..0000000 --- a/temp_sdk/soroban-sdk-26.0.1/src/xdr.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! Convert values to and from [Bytes]. -//! -//! All types that are convertible to and from [Val] implement the -//! [ToXdr] and [FromXdr] traits, and serialize to the ScVal XDR form. -//! -//! ### Examples -//! -//! ``` -//! use soroban_sdk::{ -//! xdr::{FromXdr, ToXdr}, -//! Env, Bytes, IntoVal, TryFromVal, -//! }; -//! -//! let env = Env::default(); -//! -//! let value: u32 = 5; -//! -//! let bytes = value.to_xdr(&env); -//! assert_eq!(bytes.len(), 8); -//! -//! let roundtrip = u32::from_xdr(&env, &bytes); -//! assert_eq!(roundtrip, Ok(value)); -//! ``` - -use crate::{ - env::internal::Env as _, unwrap::UnwrapInfallible, Bytes, Env, IntoVal, TryFromVal, Val, -}; - -// Re-export all the XDR from the environment. -pub use crate::env::xdr::*; - -/// Implemented by types that can be serialized to [Bytes] as XDR. -/// -/// All types that are convertible to [Val] implement this trait. The value is -/// first converted to a [Val], then serialized to XDR in its [ScVal] form. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{xdr::ToXdr, Env}; -/// -/// let env = Env::default(); -/// -/// let value: u32 = 5; -/// let bytes = value.to_xdr(&env); -/// assert_eq!(bytes.len(), 8); -/// ``` -pub trait ToXdr { - /// Serializes the value to XDR as [Bytes]. - fn to_xdr(self, env: &Env) -> Bytes; -} - -/// Implemented by types that can be deserialized from [Bytes] containing XDR. -/// -/// All types that are convertible from [Val] implement this trait. The bytes -/// are deserialized from their [ScVal] XDR form into a [Val], then converted -/// to the target type. -/// -/// ### Errors -/// -/// Returns an error if the [Val] cannot be converted into the target type. -/// -/// ### Panics -/// -/// Panics if the provided bytes are not valid XDR for an [ScVal]. -/// -/// ### Examples -/// -/// ``` -/// use soroban_sdk::{xdr::{ToXdr, FromXdr}, Env}; -/// -/// let env = Env::default(); -/// -/// let value: u32 = 5; -/// let bytes = value.to_xdr(&env); -/// -/// let roundtrip = u32::from_xdr(&env, &bytes); -/// assert_eq!(roundtrip, Ok(5)); -/// ``` -pub trait FromXdr: Sized { - /// The error type returned if the [Val] cannot be converted into the - /// target type. - type Error; - /// Deserializes the value from XDR [Bytes]. - /// - /// ### Errors - /// - /// Returns an error if the [Val] cannot be converted into the target - /// type. - /// - /// ### Panics - /// - /// Panics if the provided bytes are not valid XDR for an [ScVal]. - fn from_xdr(env: &Env, b: &Bytes) -> Result; -} - -impl ToXdr for T -where - T: IntoVal, -{ - fn to_xdr(self, env: &Env) -> Bytes { - let val: Val = self.into_val(env); - let bin = env.serialize_to_bytes(val).unwrap_infallible(); - unsafe { Bytes::unchecked_new(env.clone(), bin) } - } -} - -impl FromXdr for T -where - T: TryFromVal, -{ - type Error = T::Error; - - fn from_xdr(env: &Env, b: &Bytes) -> Result { - let t = env.deserialize_from_bytes(b.into()).unwrap_infallible(); - T::try_from_val(env, &t) - } -}