Repository: ProvableHQ/sdk (language: rust)

Issue:
[Bug] Unable to Deploy Program with Imports to Local Aleo Node
## 🐛 Bug Report

<!--
    What's the bug in Aleo that you found?
    How serious is this bug and what is affected?
    
    To report a security issue in Aleo, please email security@aleo.org.
-->

Aleo programs with multiple files (one `main.aleo` file, one imported `helper.aleo` file) cannot deploy because the [initialization in SnarkVM](https://github.com/AleoHQ/snarkVM/blob/7837e41bd2b291b8c8d6a07c22d1811fea302b9e/vm/compiler/src/process/stack/helpers/initialize.rs#L35-L44) expects the imported program to be deployed already.

## Steps to Reproduce

<!-- How do I reproduce this issue in Aleo? -->

Run `aleo node start` in a program with at least one imported aleo file.

#### Code snippet to reproduce

main.aleo file
```
import importtest.aleo;

// The 'main.aleo' program.
program token.main;

function hello:
    // Dummy input
    input r0 as address.public;
    // Dummy input
    input r1 as u64.public;
```

importtest.aleo file
```
program importtest.aleo;

function hello:
    // Dummy input
    input r0 as address.public;
    // Dummy input
    input r1 as u64.public;
```

#### Stack trace & error message

```
📦 Deploying 'token.aleo' to the local development node...

⚠️  Cannot add program 'main.aleo' because its import 'importtest.aleo' must be added first
```

## Expected Behavior

<!--
    What was supposed to happen in Aleo?
    What happened instead?
-->

Programs with local imported files should deploy successfully. Local imports should be deployed to the local Aleo Node before the main program.

## Your Environment

- Aleo Version: built from source code
- Rust Version: rustc 1.65.0-nightly
- Computer OS: macOS Monetery Version 12.5



Discussion / hints:
Thank you for catching this! Assigning it to myself to fix.

Fix patch:
diff --git a/cli/commands/node.rs b/cli/commands/node.rs
index 70c5fd947..93ba2cfc0 100644
--- a/cli/commands/node.rs
+++ b/cli/commands/node.rs
@@ -15,7 +15,7 @@
 // along with the Aleo library. If not, see <https://www.gnu.org/licenses/>.
 
 use crate::{helpers::Ledger, Network};
-use snarkvm::{file::Manifest, package::Package};
+use snarkvm::{file::Manifest, file::AleoFile, package::Package};
 
 use anyhow::{ensure, Result};
 use clap::Parser;
@@ -69,35 +69,49 @@ impl Node {
 
                 // Deploy the local program.
                 if !nodeploy {
-                    println!(
-                        "\n📦 Deploying '{}' to the local development node...\n",
-                        manifest.program_id().to_string().bold()
-                    );
-
                     // Load the package.
                     let package = Package::open(&directory)?;
                     // Load the program.
                     let program = package.program();
 
-                    // Create a deployment transaction.
-                    let transaction = ledger.create_deploy(program, 1)?;
-                    // Add the transaction to the memory pool.
-                    ledger.add_to_memory_pool(transaction.clone())?;
-
-                    // Advance to the next block.
-                    let next_block = ledger.advance_to_next_block()?;
-                    println!(
-                        "\n🛡️  Produced block {} ({})\n\n{}\n",
-                        next_block.height(),
-                        next_block.hash(),
-                        serde_json::to_string_pretty(&next_block.header())?.dimmed()
-                    );
-
-                    println!(
-                        "✅ Deployed '{}' in transaction '{}'\n",
-                        manifest.program_id().to_string().bold(),
-                        transaction.id()
-                    );
+                    // Prepare the imports directory.
+                    let imports_directory = package.imports_directory();
+
+                    // Load all of the imported programs (in order of imports).
+                    let programs = program.imports().keys().map(|program_id| {
+                        // Open the Aleo imported program file.
+                        let import_program_file = AleoFile::open(&imports_directory, program_id, false)?;
+                        // Return the imported program.
+                        Ok(import_program_file.program().clone())
+                    }).collect::<Result<Vec<_>>>()?;
+
+                    // Deploy the imported programs (in order of imports), and the main program.
+                    for program in programs.iter().chain([program.clone()].iter()) {
+                        println!(
+                            "📦 Deploying '{}' to the local development node...\n",
+                            program.id().to_string().bold()
+                        );
+
+                        // Create a deployment transaction.
+                        let transaction = ledger.create_deploy(program, 1)?;
+                        // Add the transaction to the memory pool.
+                        ledger.add_to_memory_pool(transaction.clone())?;
+
+                        // Advance to the next block.
+                        let next_block = ledger.advance_to_next_block()?;
+                        println!(
+                            "\n🛡️  Produced block {} ({})\n\n{}\n",
+                            next_block.height(),
+                            next_block.hash(),
+                            serde_json::to_string_pretty(&next_block.header())?.dimmed()
+                        );
+
+                        println!(
+                            "✅ Deployed '{}' in transaction '{}'\n",
+                            program.id().to_string().bold(),
+                            transaction.id()
+                        );
+                    }
                 }
 
                 loop {
diff --git a/cli/helpers/server.rs b/cli/helpers/server.rs
index fe889acb5..45872d80b 100644
--- a/cli/helpers/server.rs
+++ b/cli/helpers/server.rs
@@ -153,7 +153,7 @@ impl<N: Network> Server<N> {
                     .or(records_unspent)
                     .or(transaction_broadcast);
                 // Start the server.
-                println!("\n🌐 Server is running at http://0.0.0.0:4180");
+                println!("\n🌐 Server is running at http://0.0.0.0:4180\n");
                 warp::serve(routes).run(([0, 0, 0, 0], 4180)).await;
             }));
 
diff --git a/examples/external_call/README.md b/examples/external_call/README.md
new file mode 100644
index 000000000..1edd420e1
--- /dev/null
+++ b/examples/external_call/README.md
@@ -0,0 +1,38 @@
+# external_call.aleo
+
+This program demonstrates how external calls work in Aleo.
+
+In the [imports](./imports) folder, there are four basic programs:
+- [difference.aleo](./imports/difference.aleo)
+- [product.aleo](./imports/product.aleo)
+- [quotient.aleo](./imports/quotient.aleo)
+- [sum.aleo](./imports/sum.aleo)
+
+The [`main` function in `external_call.aleo`](./main.aleo) performs 4 external calls:
+```ts
+// Creates a transition that evaluates `r0 * r1`.
+call product.aleo/product r0 r1 into r2;
+
+// Creates a transition that evaluates `r2 / r1`.
+call quotient.aleo/quotient r2 r1 into r3;
+
+// Creates a transition that evaluates `r3 + r0`.
+call sum.aleo/sum r3 r0 into r4;
+
+// Creates a transition that evaluates `r4 - r3`.
+call difference.aleo/difference r4 r3 into r5;
+```
+
+## Build Guide
+
+To compile this Aleo program, run:
+```bash
+aleo build
+```
+
+## Usage
+
+To perform the external call, run:
+```bash
+aleo run main 5u32 95u32
+```
diff --git a/examples/external_call/imports/difference.aleo b/examples/external_call/imports/difference.aleo
new file mode 100644
index 000000000..2f897cd54
--- /dev/null
+++ b/examples/external_call/imports/difference.aleo
@@ -0,0 +1,9 @@
+// The 'difference.aleo' program.
+program difference.aleo;
+
+// Returns `r0 - r1`.
+function difference:
+    input r0 as u32.public;
+    input r1 as u32.private;
+    sub r0 r1 into r2;
+    output r2 as u32.private;
diff --git a/examples/external_call/imports/product.aleo b/examples/external_call/imports/product.aleo
new file mode 100644
index 000000000..bc84d97d8
--- /dev/null
+++ b/examples/external_call/imports/product.aleo
@@ -0,0 +1,9 @@
+// The 'product.aleo' program.
+program product.aleo;
+
+// Returns `r0 * r1`.
+function product:
+    input r0 as u32.public;
+    input r1 as u32.private;
+    mul r0 r1 into r2;
+    output r2 as u32.private;
diff --git a/examples/external_call/imports/quotient.aleo b/examples/external_call/imports/quotient.aleo
new file mode 100644
index 000000000..acb0d27bc
--- /dev/null
+++ b/examples/external_call/imports/quotient.aleo
@@ -0,0 +1,9 @@
+// The 'quotient.aleo' program.
+program quotient.aleo;
+
+// Returns `r0 / r1`.
+function quotient:
+    input r0 as u32.public;
+    input r1 as u32.private;
+    div r0 r1 into r2;
+    output r2 as u32.private;
diff --git a/examples/external_call/imports/sum.aleo b/examples/external_call/imports/sum.aleo
new file mode 100644
index 000000000..2c1e60538
--- /dev/null
+++ b/examples/external_call/imports/sum.aleo
@@ -0,0 +1,9 @@
+// The 'sum.aleo' program.
+program sum.aleo;
+
+// Returns `r0 + r1`.
+function sum:
+    input r0 as u32.public;
+    input r1 as u32.private;
+    add r0 r1 into r2;
+    output r2 as u32.private;
diff --git a/examples/external_call/main.aleo b/examples/external_call/main.aleo
new file mode 100644
index 000000000..5b2665bf4
--- /dev/null
+++ b/examples/external_call/main.aleo
@@ -0,0 +1,37 @@
+// Import the 'difference.aleo' program.
+import difference.aleo;
+// Import the 'product.aleo' program.
+import product.aleo;
+// Import the 'quotient.aleo' program.
+import quotient.aleo;
+// Import the 'sum.aleo' program.
+import sum.aleo;
+
+// The 'external_call.aleo' program.
+program external_call.aleo;
+
+// Performs a sequence of arithmetic calls
+// to demonstrate external calls in Aleo.
+function main:
+    // Input the first value.
+    input r0 as u32.public;
+    // Input the second value.
+    input r1 as u32.private;
+
+    // Creates a transition that evaluates `r0 * r1`.
+    call product.aleo/product r0 r1 into r2;
+
+    // Creates a transition that evaluates `r2 / r1`.
+    call quotient.aleo/quotient r2 r1 into r3;
+
+    // Creates a transition that evaluates `r3 + r0`.
+    call sum.aleo/sum r3 r0 into r4;
+
+    // Creates a transition that evaluates `r4 - r3`.
+    call difference.aleo/difference r4 r3 into r5;
+
+    // Ensure `r5 == r0`.
+    assert.eq r5 r0;
+    
+    // Return `r5`.
+    output r5 as u32.private;
diff --git a/examples/external_call/program.json b/examples/external_call/program.json
new file mode 100644
index 000000000..fdb715de5
--- /dev/null
+++ b/examples/external_call/program.json
@@ -0,0 +1,10 @@
+{
+    "program": "external_call.aleo",
+    "version": "0.0.0",
+    "description": "",
+    "development": {
+        "private_key": "APrivateKey1zkp2p4ieFsUJZ2EkudZEsxJTfw81T3qjdKjdbdWcJWKXapG",
+        "address": "aleo1f72p3g82eur6x8ysd4u6hl8rmt8un6eelpzrdsvfkp663wf6uuzs2v8cfk"
+    },
+    "license": "MIT"
+}


Test patch: