From 7cde107583bdc3c3e3380e7469b1c91fa84a89e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaya=20G=C3=B6kalp?= Date: Thu, 1 Sep 2022 14:57:42 -0700 Subject: [PATCH 1/3] refactor: forc-deploy requires wallet address and accepts signature (#2629) --- Cargo.lock | 356 ++++++++++++++++-- forc-plugins/forc-client/Cargo.toml | 6 +- .../forc-client/src/ops/deploy/cmd.rs | 9 + forc-plugins/forc-client/src/ops/deploy/op.rs | 112 +++++- forc-plugins/forc-client/src/ops/mod.rs | 1 + .../src/ops/{run => }/parameters.rs | 0 forc-plugins/forc-client/src/ops/run/cmd.rs | 4 - forc-plugins/forc-client/src/ops/run/mod.rs | 1 - forc-plugins/forc-client/src/ops/run/op.rs | 2 +- test/src/e2e_vm_tests/harness.rs | 1 + 10 files changed, 448 insertions(+), 44 deletions(-) rename forc-plugins/forc-client/src/ops/{run => }/parameters.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index f7b4e10b68f..50eca5c5b21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,7 +29,19 @@ checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" dependencies = [ "aes-soft", "aesni", - "cipher", + "cipher 0.2.5", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.3.0", + "cpufeatures", + "opaque-debug 0.3.0", ] [[package]] @@ -39,9 +51,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" dependencies = [ "aead", - "aes", - "cipher", - "ctr", + "aes 0.6.0", + "cipher 0.2.5", + "ctr 0.6.0", "ghash", "subtle", ] @@ -52,7 +64,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" dependencies = [ - "cipher", + "cipher 0.2.5", "opaque-debug 0.3.0", ] @@ -62,7 +74,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" dependencies = [ - "cipher", + "cipher 0.2.5", "opaque-debug 0.3.0", ] @@ -212,9 +224,9 @@ dependencies = [ [[package]] name = "async-io" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab006897723d9352f63e2b13047177c3982d8d79709d713ce7747a8f19fd1b0" +checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" dependencies = [ "autocfg", "concurrent-queue", @@ -382,6 +394,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "beef" version = "0.5.2" @@ -448,7 +466,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding", + "block-padding 0.1.5", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -460,6 +478,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ + "block-padding 0.2.1", "generic-array 0.14.6", ] @@ -481,6 +500,12 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + [[package]] name = "blocking" version = "1.2.0" @@ -552,6 +577,9 @@ name = "bytes" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +dependencies = [ + "serde", +] [[package]] name = "cache-padded" @@ -605,6 +633,15 @@ dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "clap" version = "2.34.0" @@ -698,7 +735,7 @@ dependencies = [ "getrandom 0.2.7", "hex", "hmac 0.12.1", - "pbkdf2", + "pbkdf2 0.11.0", "rand 0.8.5", "sha2 0.10.3", "thiserror", @@ -712,7 +749,7 @@ checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" dependencies = [ "base58check", "base64 0.12.3", - "bech32", + "bech32 0.7.3", "blake2", "digest 0.10.3", "generic-array 0.14.6", @@ -721,7 +758,7 @@ dependencies = [ "serde", "serde_derive", "sha2 0.10.3", - "sha3", + "sha3 0.10.2", "thiserror", ] @@ -768,6 +805,12 @@ dependencies = [ "serde", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "const-oid" version = "0.9.0" @@ -862,6 +905,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "crypto-bigint" version = "0.4.8" @@ -894,6 +949,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + [[package]] name = "csv" version = "1.1.6" @@ -932,7 +997,16 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" dependencies = [ - "cipher", + "cipher 0.2.5", +] + +[[package]] +name = "ctr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" +dependencies = [ + "cipher 0.3.0", ] [[package]] @@ -1037,13 +1111,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid 0.7.1", +] + [[package]] name = "der" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" dependencies = [ - "const-oid", + "const-oid 0.9.0", "zeroize", ] @@ -1147,8 +1230,8 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e852f4174d2a8646a0fa8a34b55797856c722f86267deb0aa1e93f7f247f800e" dependencies = [ - "der", - "elliptic-curve", + "der 0.6.0", + "elliptic-curve 0.12.3", "rfc6979", "signature", ] @@ -1159,6 +1242,21 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint 0.3.2", + "der 0.5.1", + "generic-array 0.14.6", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + [[package]] name = "elliptic-curve" version = "0.12.3" @@ -1166,8 +1264,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ "base16ct", - "crypto-bigint", - "der", + "crypto-bigint 0.4.8", + "der 0.6.0", "digest 0.10.3", "ff", "generic-array 0.14.6", @@ -1207,6 +1305,28 @@ dependencies = [ "termcolor", ] +[[package]] +name = "eth-keystore" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47d900a7dea08593d398104f8288e37858b0ad714c8d08cd03fdb86563e6402" +dependencies = [ + "aes 0.7.5", + "ctr 0.7.0", + "digest 0.9.0", + "hex", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.9.9", + "sha3 0.9.1", + "thiserror", + "uuid", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -1339,9 +1459,13 @@ dependencies = [ "clap 3.2.19", "forc-pkg", "forc-util", + "fuel-crypto", "fuel-gql-client", "fuel-tx", "fuel-vm", + "fuels-core", + "fuels-signers", + "fuels-types", "futures", "hex", "serde", @@ -1577,12 +1701,80 @@ dependencies = [ "rand 0.8.5", "secp256k1 0.24.0", "serde", - "sha3", + "sha3 0.10.2", "tai64", "thiserror", "tracing", ] +[[package]] +name = "fuels-core" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d60c30cabd0a7c08b634937284a4d2e4a5c7d29daf6f6b4630743f1f474d5a7" +dependencies = [ + "Inflector", + "anyhow", + "fuel-tx", + "fuel-types", + "fuels-types", + "hex", + "itertools", + "proc-macro2", + "quote", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "sha2 0.9.9", + "strum", + "strum_macros", + "syn", + "thiserror", +] + +[[package]] +name = "fuels-signers" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fa8399ede6717438eb8429d0a3d6852b60abe7a29a456c5f1d1870c571ac02a" +dependencies = [ + "async-trait", + "bytes", + "elliptic-curve 0.11.12", + "eth-keystore", + "fuel-crypto", + "fuel-gql-client", + "fuel-types", + "fuels-core", + "fuels-types", + "hex", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "thiserror", + "tokio", +] + +[[package]] +name = "fuels-types" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6097a178b4f5afae612010f97b92aefd62cdc4673195e7d39681cdc15cd51d" +dependencies = [ + "anyhow", + "bech32 0.9.1", + "fuel-tx", + "hex", + "proc-macro2", + "serde", + "serde_json", + "strum", + "strum_macros", + "thiserror", + "tokio", +] + [[package]] name = "futures" version = "0.3.24" @@ -1932,7 +2124,17 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ - "crypto-mac", + "crypto-mac 0.10.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", "digest 0.9.0", ] @@ -2197,7 +2399,7 @@ checksum = "6db2573d3fd3e4cc741affc9b5ce1a8ce36cf29f09f80f36da4309d0ae6d7854" dependencies = [ "cfg-if 1.0.0", "ecdsa", - "elliptic-curve", + "elliptic-curve 0.12.3", "sha2 0.10.3", ] @@ -2597,6 +2799,16 @@ dependencies = [ "parking_lot_core 0.8.5", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + [[package]] name = "parking_lot_core" version = "0.8.5" @@ -2624,6 +2836,17 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "password-hash" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "password-hash" version = "0.4.2" @@ -2641,6 +2864,19 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "base64ct", + "crypto-mac 0.11.1", + "hmac 0.11.0", + "password-hash 0.2.3", + "sha2 0.9.9", +] + [[package]] name = "pbkdf2" version = "0.11.0" @@ -2649,7 +2885,7 @@ checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest 0.10.3", "hmac 0.12.1", - "password-hash", + "password-hash 0.4.2", "sha2 0.10.3", ] @@ -2824,7 +3060,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", + "der 0.6.0", "spki", ] @@ -3169,7 +3405,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.8", "hmac 0.12.1", "zeroize", ] @@ -3303,6 +3539,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" +[[package]] +name = "salsa20" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" +dependencies = [ + "cipher 0.3.0", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3350,6 +3595,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scrypt" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879588d8f90906e73302547e20fffefdd240eb3e0e744e142321f5d49dea0518" +dependencies = [ + "base64ct", + "hmac 0.11.0", + "password-hash 0.2.3", + "pbkdf2 0.8.0", + "salsa20", + "sha2 0.9.9", +] + [[package]] name = "sct" version = "0.6.1" @@ -3377,7 +3636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct", - "der", + "der 0.6.0", "generic-array 0.14.6", "pkcs8", "subtle", @@ -3594,6 +3853,18 @@ dependencies = [ "digest 0.10.3", ] +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.0", +] + [[package]] name = "sha3" version = "0.10.2" @@ -3701,7 +3972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.0", ] [[package]] @@ -3810,6 +4081,24 @@ dependencies = [ "syn", ] +[[package]] +name = "strum" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" + +[[package]] +name = "strum_macros" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subtle" version = "2.4.1" @@ -4099,7 +4388,7 @@ dependencies = [ "fuel-vm", "hex", "secp256k1 0.20.3", - "sha3", + "sha3 0.10.2", "tracing", ] @@ -4230,6 +4519,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -4624,6 +4914,16 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.7", + "serde", +] + [[package]] name = "uwuify" version = "0.2.2" @@ -4632,7 +4932,7 @@ checksum = "3db6840b7adcfd2e866c79157cc890ecdbbc1f739607134039ae64eaa6c07e24" dependencies = [ "clap 2.34.0", "owo-colors", - "parking_lot", + "parking_lot 0.11.2", "thiserror", ] diff --git a/forc-plugins/forc-client/Cargo.toml b/forc-plugins/forc-client/Cargo.toml index 8d59835c6a7..edef15438ca 100644 --- a/forc-plugins/forc-client/Cargo.toml +++ b/forc-plugins/forc-client/Cargo.toml @@ -13,12 +13,16 @@ anyhow = "1" clap = { version = "3", features = ["derive", "env"] } forc-pkg = { version = "0.22.1", path = "../../forc-pkg" } forc-util = { version = "0.22.1", path = "../../forc-util" } +fuel-crypto = "0.6" fuel-gql-client = { version = "0.10", default-features = false } fuel-tx = "0.18" fuel-vm = "0.15" +fuels-core = "0.21" +fuels-signers = "0.21" +fuels-types = "0.21" futures = "0.3" hex = "0.4.3" -serde = { version = "1.0" } +serde = "1.0" serde_json = "1.0.73" sway-core = { version = "0.22.1", path = "../../sway-core" } sway-types = { version = "0.22.1", path = "../../sway-types" } diff --git a/forc-plugins/forc-client/src/ops/deploy/cmd.rs b/forc-plugins/forc-client/src/ops/deploy/cmd.rs index 8972a5954f4..827031e3cdd 100644 --- a/forc-plugins/forc-client/src/ops/deploy/cmd.rs +++ b/forc-plugins/forc-client/src/ops/deploy/cmd.rs @@ -69,4 +69,13 @@ pub struct DeployCommand { /// Output the time elapsed over each part of the compilation process. #[clap(long)] pub time_phases: bool, + /// Do not sign the transaction + #[clap(long)] + pub unsigned: bool, + /// Set the transaction gas limit. Defaults to the maximum gas limit. + #[clap(long)] + pub gas_limit: Option, + /// Set the transaction gas price. Defaults to 0. + #[clap(long)] + pub gas_price: Option, } diff --git a/forc-plugins/forc-client/src/ops/deploy/op.rs b/forc-plugins/forc-client/src/ops/deploy/op.rs index 438b3b99560..94d6b8c53c6 100644 --- a/forc-plugins/forc-client/src/ops/deploy/op.rs +++ b/forc-plugins/forc-client/src/ops/deploy/op.rs @@ -1,14 +1,18 @@ use anyhow::{bail, Result}; -use forc_pkg::{BuildOptions, ManifestFile}; +use forc_pkg::{BuildOptions, Compiled, ManifestFile}; +use fuel_crypto::Signature; use fuel_gql_client::client::FuelClient; use fuel_tx::{Output, Salt, StorageSlot, Transaction}; use fuel_vm::prelude::*; -use std::path::PathBuf; +use fuels_core::constants::{BASE_ASSET_ID, DEFAULT_SPENDABLE_COIN_AMOUNT}; +use fuels_signers::{provider::Provider, wallet::Wallet}; +use fuels_types::bech32::Bech32Address; +use std::{io::Write, path::PathBuf, str::FromStr}; use sway_core::TreeType; use sway_utils::constants::DEFAULT_NODE_URL; use tracing::info; -use super::cmd::DeployCommand; +use crate::ops::{deploy::cmd::DeployCommand, parameters::TxParameters}; pub async fn deploy(command: DeployCommand) -> Result { let curr_dir = if let Some(ref path) = command.path { @@ -37,6 +41,9 @@ pub async fn deploy(command: DeployCommand) -> Result { build_profile, release, time_phases, + unsigned, + gas_limit, + gas_price, } = command; let build_options = BuildOptions { @@ -59,12 +66,6 @@ pub async fn deploy(command: DeployCommand) -> Result { }; let compiled = forc_pkg::build_with_options(build_options)?; - let (tx, contract_id) = create_contract_tx( - compiled.bytecode, - Vec::::new(), - Vec::::new(), - compiled.storage_slots, - ); let node_url = match &manifest.network { Some(network) => &network.url, @@ -75,6 +76,47 @@ pub async fn deploy(command: DeployCommand) -> Result { let client = FuelClient::new(node_url)?; + let (mut tx, contract_id) = if unsigned { + create_contract_tx( + compiled.bytecode, + Vec::::new(), + Vec::::new(), + compiled.storage_slots, + ) + } else { + let mut wallet_address = String::new(); + print!( + "Please provide the address of the wallet you are going to sign this transaction with:" + ); + std::io::stdout().flush()?; + std::io::stdin().read_line(&mut wallet_address)?; + let address = Bech32Address::from_str(wallet_address.trim())?; + let locked_wallet = Wallet::from_address(address, Some(Provider::new(client.clone()))); + let tx_parameters = TxParameters::new(gas_limit, gas_price); + create_signed_contract_tx(compiled, locked_wallet, tx_parameters).await? + }; + + if !unsigned { + // Ask for the signature and add it as a witness + let mut signature = String::new(); + print!("Please provide the signature for this transaction:"); + std::io::stdout().flush()?; + std::io::stdin().read_line(&mut signature)?; + + let signature = Signature::from_str(signature.trim())?; + let witness = vec![Witness::from(signature.as_ref())]; + + let mut witnesses: Vec = tx.witnesses().to_vec(); + + match witnesses.len() { + 0 => tx.set_witnesses(witness), + _ => { + witnesses.extend(witness); + tx.set_witnesses(witnesses) + } + } + } + match client.submit(&tx).await { Ok(logs) => { info!("Logs:\n{:?}", logs); @@ -84,6 +126,58 @@ pub async fn deploy(command: DeployCommand) -> Result { } } +async fn create_signed_contract_tx( + compiled_contract: Compiled, + signer_wallet: Wallet, + tx_parameters: TxParameters, +) -> Result<(Transaction, fuel_tx::ContractId)> { + let maturity = 0; + let bytecode_witness_index = 0; + let witnesses = vec![compiled_contract.bytecode.clone().into()]; + + let salt = Salt::new([0; 32]); + + let contract = Contract::from(compiled_contract.bytecode); + let root = contract.root(); + + let mut storage_slots = compiled_contract.storage_slots; + storage_slots.sort(); + let state_root = Contract::initial_state_root(storage_slots.iter()); + let contract_id = contract.id(&salt, &root, &state_root); + info!("Contract id: 0x{}", hex::encode(contract_id)); + + let outputs: Vec = vec![ + Output::contract_created(contract_id, state_root), + // Note that the change will be computed by the node. + // Here we only have to tell the node who will own the change and its asset ID. + // For now we use the BASE_ASSET_ID constant + Output::change(signer_wallet.address().into(), 0, BASE_ASSET_ID), + ]; + let coin_witness_index = 1; + + let inputs = signer_wallet + .get_asset_inputs_for_amount( + AssetId::default(), + DEFAULT_SPENDABLE_COIN_AMOUNT, + coin_witness_index, + ) + .await?; + let tx = Transaction::create( + tx_parameters.gas_price, + tx_parameters.gas_limit, + maturity, + bytecode_witness_index, + salt, + storage_slots, + inputs, + outputs, + witnesses, + ); + + println!("Tx id to sign {}", tx.id()); + Ok((tx, contract_id)) +} + fn create_contract_tx( compiled_contract: Vec, inputs: Vec, diff --git a/forc-plugins/forc-client/src/ops/mod.rs b/forc-plugins/forc-client/src/ops/mod.rs index a34b52a23c3..4833d0b18f4 100644 --- a/forc-plugins/forc-client/src/ops/mod.rs +++ b/forc-plugins/forc-client/src/ops/mod.rs @@ -1,2 +1,3 @@ pub mod deploy; +pub mod parameters; pub mod run; diff --git a/forc-plugins/forc-client/src/ops/run/parameters.rs b/forc-plugins/forc-client/src/ops/parameters.rs similarity index 100% rename from forc-plugins/forc-client/src/ops/run/parameters.rs rename to forc-plugins/forc-client/src/ops/parameters.rs diff --git a/forc-plugins/forc-client/src/ops/run/cmd.rs b/forc-plugins/forc-client/src/ops/run/cmd.rs index 6a8243c5127..4095f734626 100644 --- a/forc-plugins/forc-client/src/ops/run/cmd.rs +++ b/forc-plugins/forc-client/src/ops/run/cmd.rs @@ -91,10 +91,6 @@ pub struct RunCommand { #[clap(long)] pub minify_json_storage_slots: bool, - /// Set the transaction byte price. Defaults to 0. - #[clap(long)] - pub byte_price: Option, - /// Set the transaction gas limit. Defaults to the maximum gas limit. #[clap(long)] pub gas_limit: Option, diff --git a/forc-plugins/forc-client/src/ops/run/mod.rs b/forc-plugins/forc-client/src/ops/run/mod.rs index defc2c64c3a..8d8565f9f78 100644 --- a/forc-plugins/forc-client/src/ops/run/mod.rs +++ b/forc-plugins/forc-client/src/ops/run/mod.rs @@ -1,3 +1,2 @@ pub mod cmd; pub mod op; -mod parameters; diff --git a/forc-plugins/forc-client/src/ops/run/op.rs b/forc-plugins/forc-client/src/ops/run/op.rs index 6c83a2b5061..9da0d8e8098 100644 --- a/forc-plugins/forc-client/src/ops/run/op.rs +++ b/forc-plugins/forc-client/src/ops/run/op.rs @@ -7,7 +7,7 @@ use std::{path::PathBuf, str::FromStr}; use sway_core::TreeType; use tracing::info; -use super::{cmd::RunCommand, parameters::TxParameters}; +use crate::ops::{parameters::TxParameters, run::cmd::RunCommand}; pub const NODE_URL: &str = "http://127.0.0.1:4000"; diff --git a/test/src/e2e_vm_tests/harness.rs b/test/src/e2e_vm_tests/harness.rs index 46749b8c8a1..d44278fdf7c 100644 --- a/test/src/e2e_vm_tests/harness.rs +++ b/test/src/e2e_vm_tests/harness.rs @@ -29,6 +29,7 @@ pub(crate) fn deploy_contract(file_name: &str, locked: bool) -> ContractId { )), silent_mode: !verbose, locked, + unsigned: true, ..Default::default() })) .unwrap() From ecf537a5c892ddab7997a34d9a128007cfdd91fc Mon Sep 17 00:00:00 2001 From: Emily Herbert <17410721+emilyaherbert@users.noreply.github.com> Date: Thu, 1 Sep 2022 17:22:45 -0500 Subject: [PATCH 2/3] Add the `CopyTypes` trait to `DeclarationId` (#2682) Co-authored-by: Toby Hutton --- .../src/declaration_engine/declaration_id.rs | 8 ++++++++ .../src/declaration_engine/declaration_wrapper.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/sway-core/src/declaration_engine/declaration_id.rs b/sway-core/src/declaration_engine/declaration_id.rs index 5b7e2efdbee..19225744762 100644 --- a/sway-core/src/declaration_engine/declaration_id.rs +++ b/sway-core/src/declaration_engine/declaration_id.rs @@ -2,6 +2,8 @@ use std::fmt; use sway_types::{Span, Spanned}; +use crate::type_system::{CopyTypes, TypeMapping}; + use super::declaration_engine::de_look_up_decl_id; /// An ID used to refer to an item in the [DeclarationEngine](super::declaration_engine::DeclarationEngine) @@ -49,6 +51,12 @@ impl Spanned for DeclarationId { } } +impl CopyTypes for DeclarationId { + fn copy_types(&mut self, type_mapping: &TypeMapping) { + de_look_up_decl_id(self.clone()).copy_types(type_mapping) + } +} + impl DeclarationId { pub(super) fn new(index: usize, span: Span) -> DeclarationId { DeclarationId(index, span) diff --git a/sway-core/src/declaration_engine/declaration_wrapper.rs b/sway-core/src/declaration_engine/declaration_wrapper.rs index 5924b7cd34e..97cc7d64ac9 100644 --- a/sway-core/src/declaration_engine/declaration_wrapper.rs +++ b/sway-core/src/declaration_engine/declaration_wrapper.rs @@ -7,6 +7,7 @@ use crate::{ TypedImplTrait, TypedStorageDeclaration, TypedStructDeclaration, TypedTraitDeclaration, TypedTraitFn, }, + type_system::{CopyTypes, TypeMapping}, CompileError, TypedFunctionDeclaration, }; @@ -54,6 +55,20 @@ impl fmt::Display for DeclarationWrapper { } } +impl CopyTypes for DeclarationWrapper { + fn copy_types(&mut self, type_mapping: &TypeMapping) { + match self { + DeclarationWrapper::Unknown => {} + DeclarationWrapper::Function(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::Trait(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::TraitFn(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::TraitImpl(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::Struct(decl) => decl.copy_types(type_mapping), + DeclarationWrapper::Storage(_) => {} + } + } +} + impl DeclarationWrapper { /// friendly name string used for error reporting. fn friendly_name(&self) -> &'static str { From 612b028e44f30e76757a5ad1d7d16b16e8efe756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaya=20G=C3=B6kalp?= Date: Thu, 1 Sep 2022 19:09:59 -0700 Subject: [PATCH 3/3] fix: Unformatted comment spans add extra newline (#2692) * newline handler checks for existing newlines before inserting new ones * stability test added * newline-comment handler interaction test added * review suggestion --- sway-fmt-v2/src/formatter/mod.rs | 98 +++++++++++++++++++++------- sway-fmt-v2/src/items/item_trait.rs | 4 +- sway-fmt-v2/src/utils/map/newline.rs | 21 +++++- 3 files changed, 98 insertions(+), 25 deletions(-) diff --git a/sway-fmt-v2/src/formatter/mod.rs b/sway-fmt-v2/src/formatter/mod.rs index 2476c18a2c5..c50ecf84b44 100644 --- a/sway-fmt-v2/src/formatter/mod.rs +++ b/sway-fmt-v2/src/formatter/mod.rs @@ -99,6 +99,14 @@ mod tests { use crate::config::user_def::FieldAlignment; use std::sync::Arc; + /// Checks if the formatter is producing the same output when given it's output. + fn test_stability(formatted_input: String, formatter: Formatter) -> bool { + let mut formatter = formatter; + let formatted_sway_code = + Formatter::format(&mut formatter, Arc::from(formatted_input.clone()), None).unwrap(); + formatted_input == formatted_sway_code + } + #[test] fn test_const() { let sway_code_to_format = r#"contract; @@ -109,7 +117,8 @@ pub const TEST: u16 = 10; let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -131,7 +140,8 @@ pub struct Foo { formatter.config.structures.field_alignment = FieldAlignment::AlignFields(40); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_struct() { @@ -150,7 +160,8 @@ pub struct Foo { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -176,7 +187,8 @@ enum Color { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_enum_with_variant_alignment() { @@ -205,7 +217,8 @@ enum Color { let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_item_abi_with_generics_and_attributes() { @@ -228,7 +241,8 @@ abi StorageMapExample { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -246,7 +260,8 @@ pub const TEST1: u16 = 10; let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_ty_formatting() { @@ -283,6 +298,7 @@ enum TestTy { let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_storage_without_alignment() { @@ -318,7 +334,8 @@ storage { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_storage_with_alignment() { @@ -355,7 +372,8 @@ storage { formatter.config.structures.field_alignment = FieldAlignment::AlignFields(50); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_storage_initializer() { @@ -407,7 +425,8 @@ storage { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_item_fn() { @@ -429,7 +448,8 @@ fn goodbye() -> usize { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_same_line_where() { @@ -449,7 +469,8 @@ where let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_trait_and_super_trait() { @@ -463,7 +484,6 @@ trait CompSciStudent: Programmer+Student {fn git_username(self) -> String;}"#; trait Person { fn name(self) -> String; - fn age(self) -> usize; } trait Student: Person { @@ -479,7 +499,8 @@ trait CompSciStudent: Programmer + Student { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_method_calls() { @@ -573,7 +594,8 @@ fn main() -> bool { formatter.config.whitespace.max_width = 220; let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -623,7 +645,8 @@ pub struct Foo { // Here is a comment let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -655,6 +678,7 @@ pub enum Bazz { // Here is a comment let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -677,6 +701,7 @@ fn hello_world(baz: /* this is a comment */ u64) { let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -702,6 +727,7 @@ abi StorageMapExample { let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -715,6 +741,7 @@ pub const /* TEST: blah blah tests */ TEST: u16 = 10; // This is a comment next let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_storage_comments() { @@ -751,6 +778,7 @@ storage { let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -772,7 +800,8 @@ trait Programmer { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -793,7 +822,8 @@ where /* This is next to where */ let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] fn test_impl() { @@ -839,7 +869,8 @@ impl Qux for Foo where let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -880,7 +911,8 @@ impl Qux for Foo { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -914,7 +946,8 @@ fn main() { let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } #[test] @@ -946,6 +979,27 @@ fn main() {} let mut formatter = Formatter::default(); let formatted_sway_code = Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); - assert_eq!(correct_sway_code, formatted_sway_code) + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); + } + + #[test] + fn test_newline_comment_handler_interaction() { + let sway_code_to_format = r#"script; + +// use statements +use std::*;"#; + + let correct_sway_code = r#"script; + +// use statements +use std::*; +"#; + + let mut formatter = Formatter::default(); + let formatted_sway_code = + Formatter::format(&mut formatter, Arc::from(sway_code_to_format), None).unwrap(); + assert_eq!(correct_sway_code, formatted_sway_code); + assert!(test_stability(formatted_sway_code, formatter)); } } diff --git a/sway-fmt-v2/src/items/item_trait.rs b/sway-fmt-v2/src/items/item_trait.rs index f315188590b..f1f882b6bdb 100644 --- a/sway-fmt-v2/src/items/item_trait.rs +++ b/sway-fmt-v2/src/items/item_trait.rs @@ -42,7 +42,7 @@ impl Format for ItemTrait { formatter.shape.indent.to_string(&formatter.config)?, )?; fn_signature.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}\n", semicolon_token.ident().as_str())?; + writeln!(formatted_code, "{}", semicolon_token.ident().as_str())?; } formatted_code.pop(); // pop last ending newline if let Some(trait_defs) = &self.trait_defs_opt { @@ -89,7 +89,7 @@ impl CurlyBrace for ItemTrait { formatter: &mut Formatter, ) -> Result<(), FormatterError> { formatter.shape.block_unindent(&formatter.config); - write!(line, "{}", Delimiter::Brace.as_close_char())?; + write!(line, "\n{}", Delimiter::Brace.as_close_char())?; Ok(()) } } diff --git a/sway-fmt-v2/src/utils/map/newline.rs b/sway-fmt-v2/src/utils/map/newline.rs index e186ff6db0e..908b9ce36ff 100644 --- a/sway-fmt-v2/src/utils/map/newline.rs +++ b/sway-fmt-v2/src/utils/map/newline.rs @@ -172,6 +172,23 @@ fn format_newline_sequnce(newline_sequence: &NewlineSequence, threshold: usize) } } +/// Checks for newlines that are already in the source code. +fn find_already_present_extra_newlines(from: usize, src: String) -> usize { + let mut number_of_newlines_present = 0; + for char in src.chars().skip(from) { + if char == '\n' { + number_of_newlines_present += 1; + } else { + break; + } + } + if number_of_newlines_present == 0 { + 0 + } else { + number_of_newlines_present - 1 + } +} + /// Inserts after given span and returns the offset. fn insert_after_span( from: &ByteSpan, @@ -182,7 +199,9 @@ fn insert_after_span( ) -> Result { let iter = newline_sequences_to_insert.iter(); let mut sequence_string = String::new(); - for newline_sequence in iter { + let newlines_to_skip = + find_already_present_extra_newlines(from.end, formatted_code.to_string()); + for newline_sequence in iter.skip(newlines_to_skip) { write!( sequence_string, "{}",