diff --git a/.github/actions/setup-solana/action.yaml b/.github/actions/setup-solana/action.yaml index af7c3946d0..6ce55173fa 100644 --- a/.github/actions/setup-solana/action.yaml +++ b/.github/actions/setup-solana/action.yaml @@ -10,7 +10,7 @@ runs: path: | ~/.cache/solana/ ~/.local/share/solana/ - key: solana-${{ runner.os }}-v0000-${{ env.SOLANA_CLI_VERSION }} + key: solana-${{ runner.os }}-v0000-${{ env.SOLANA_CLI_VERSION }}-${{ env.SOLANG_VERSION }} - uses: nick-fields/retry@v2 if: steps.cache-solana.outputs.cache-hit != 'true' with: @@ -20,6 +20,18 @@ runs: retry_on: error shell: bash command: sh -c "$(curl -sSfL https://release.solana.com/v${{ env.SOLANA_CLI_VERSION }}/install)" + - uses: nick-fields/retry@v2 + if: steps.cache-solana.outputs.cache-hit != 'true' + with: + retry_wait_seconds: 300 + timeout_minutes: 2 + max_attempts: 10 + retry_on: error + shell: bash + command: | + curl -sSL -o /home/runner/.local/share/solana/install/active_release/bin/solang \ + https://github.com/hyperledger/solang/releases/download/v${{ env.SOLANG_VERSION }}/solang-linux-x86-64 + chmod 755 /home/runner/.local/share/solana/install/active_release/bin/solang - run: echo "/home/runner/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH shell: bash - run: solana-keygen new --no-bip39-passphrase diff --git a/.github/workflows/no-caching-tests.yaml b/.github/workflows/no-caching-tests.yaml index 3338e84c91..c606a2ecd3 100644 --- a/.github/workflows/no-caching-tests.yaml +++ b/.github/workflows/no-caching-tests.yaml @@ -12,6 +12,7 @@ jobs: with: cache: false solana_cli_version: 1.16.0 + solang_version: 0.3.2 node_version: 17.0.1 cargo_profile: release anchor_binary_name: anchor-binary-no-caching diff --git a/.github/workflows/reusable-tests.yaml b/.github/workflows/reusable-tests.yaml index 8941170d30..7c297cf87b 100644 --- a/.github/workflows/reusable-tests.yaml +++ b/.github/workflows/reusable-tests.yaml @@ -9,6 +9,9 @@ on: solana_cli_version: required: true type: string + solang_version: + required: true + type: string node_version: required: true type: string @@ -21,6 +24,7 @@ on: env: CACHE: inputs.cache SOLANA_CLI_VERSION: ${{ inputs.solana_cli_version }} + SOLANG_VERSION: ${{ inputs.solang_version }} NODE_VERSION: ${{ inputs.node_version }} CARGO_PROFILE: ${{ inputs.cargo_profile }} ANCHOR_BINARY_NAME: ${{ inputs.anchor_binary_name }} @@ -445,6 +449,8 @@ jobs: path: tests/bench - cmd: cd tests/idl && ./test.sh path: tests/idl + - cmd: cd tests/solang && anchor test + path: tests/solang steps: - uses: actions/checkout@v3 - uses: ./.github/actions/setup/ diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index bf903d19fe..5f3602b998 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -15,6 +15,7 @@ jobs: with: cache: true solana_cli_version: 1.16.0 + solang_version: 0.3.2 node_version: 17.0.1 cargo_profile: debug anchor_binary_name: anchor-binary diff --git a/Cargo.lock b/Cargo.lock index 301ecad048..7a255b707e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2189,6 +2189,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.6" @@ -4504,11 +4513,11 @@ dependencies = [ [[package]] name = "solang-parser" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c792fe9fae2a2f716846f214ca10d5a1e21133e0bf36cef34bcc4a852467b21" +checksum = "7cb9fa2fa2fa6837be8a2495486ff92e3ffe68a99b6eeba288e139efdd842457" dependencies = [ - "itertools 0.10.5", + "itertools 0.11.0", "lalrpop", "lalrpop-util", "phf", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index b265f72eae..87bb7ad847 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -41,7 +41,7 @@ solana-cli-config = ">=1.14, <1.17" solana-faucet = ">=1.14, <1.17" solana-program = ">=1.14, <1.17" solana-sdk = ">=1.14, <1.17" -solang-parser = "=0.3.1" +solang-parser = "=0.3.2" syn = { version = "1.0.60", features = ["full", "extra-traits"] } tar = "0.4.35" toml = "0.7.6" diff --git a/cli/src/config.rs b/cli/src/config.rs index fcbdae23f1..e5277d9d16 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -114,6 +114,8 @@ impl Manifest { let mut cwd_opt = Some(start_from.as_path()); while let Some(cwd) = cwd_opt { + let mut anchor_toml = false; + for f in fs::read_dir(cwd).with_context(|| { format!("Error reading the directory with path: {}", cwd.display()) })? { @@ -127,10 +129,17 @@ impl Manifest { let m = WithPath::new(Manifest::from_path(&p)?, p); return Ok(Some(m)); } + if filename.to_str() == Some("Anchor.toml") { + anchor_toml = true; + } } } - // Not found. Go up a directory level. + // Not found. Go up a directory level, but don't go up from Anchor.toml + if anchor_toml { + break; + } + cwd_opt = cwd.parent(); } diff --git a/cli/src/solidity_template.rs b/cli/src/solidity_template.rs index f1211bda67..4a2c33cc5a 100644 --- a/cli/src/solidity_template.rs +++ b/cli/src/solidity_template.rs @@ -133,7 +133,7 @@ contract {} {{ bool private value = true; @payer(payer) - constructor(address payer) {{ + constructor() {{ print("Hello, World!"); }} @@ -318,22 +318,27 @@ describe("{}", () => {{ it("Is initialized!", async () => {{ // Add your test here. - const tx = await program.methods.new(wallet.publicKey) + const tx = await program.methods + .new() .accounts({{ dataAccount: dataAccount.publicKey }}) - .signers([dataAccount]).rpc(); + .signers([dataAccount]) + .rpc(); console.log("Your transaction signature", tx); - const val1 = await program.methods.get() + const val1 = await program.methods + .get() .accounts({{ dataAccount: dataAccount.publicKey }}) .view(); console.log("state", val1); - await program.methods.flip() + await program.methods + .flip() .accounts({{ dataAccount: dataAccount.publicKey }}) .rpc(); - const val2 = await program.methods.get() + const val2 = await program.methods + .get() .accounts({{ dataAccount: dataAccount.publicKey }}) .view(); @@ -366,9 +371,11 @@ describe("{}", () => {{ it("Is initialized!", async () => {{ // Add your test here. - const tx = await program.methods.new(wallet.publicKey) + const tx = await program.methods + .new() .accounts({{ dataAccount: dataAccount.publicKey }}) - .signers([dataAccount]).rpc(); + .signers([dataAccount]) + .rpc(); console.log("Your transaction signature", tx); }}); }}); diff --git a/tests/package.json b/tests/package.json index ea3488b888..bb619e9505 100644 --- a/tests/package.json +++ b/tests/package.json @@ -43,7 +43,8 @@ "cpi-returns", "multiple-suites", "multiple-suites-run-single", - "bpf-upgradeable-state" + "bpf-upgradeable-state", + "solang" ], "dependencies": { "@project-serum/common": "^0.0.1-beta.3", diff --git a/tests/solang/.gitignore b/tests/solang/.gitignore new file mode 100644 index 0000000000..8d401163fb --- /dev/null +++ b/tests/solang/.gitignore @@ -0,0 +1,8 @@ + +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/tests/solang/.prettierignore b/tests/solang/.prettierignore new file mode 100644 index 0000000000..c1a0b75f09 --- /dev/null +++ b/tests/solang/.prettierignore @@ -0,0 +1,8 @@ + +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/tests/solang/Anchor.toml b/tests/solang/Anchor.toml new file mode 100644 index 0000000000..01d79cad86 --- /dev/null +++ b/tests/solang/Anchor.toml @@ -0,0 +1,13 @@ +[features] +seeds = false +skip-lint = false + +[programs.localnet] +flipper = "F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC" + +[provider] +cluster = "Localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/tests/solang/migrations/deploy.ts b/tests/solang/migrations/deploy.ts new file mode 100644 index 0000000000..82fb175fa2 --- /dev/null +++ b/tests/solang/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +const anchor = require("@coral-xyz/anchor"); + +module.exports = async function (provider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/tests/solang/package.json b/tests/solang/package.json new file mode 100644 index 0000000000..41156d745c --- /dev/null +++ b/tests/solang/package.json @@ -0,0 +1,19 @@ +{ + "name": "solang", + "version": "0.28.0", + "license": "(MIT OR Apache-2.0)", + "homepage": "https://github.com/coral-xyz/anchor#readme", + "bugs": { + "url": "https://github.com/coral-xyz/anchor/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/coral-xyz/anchor.git" + }, + "engines": { + "node": ">=11" + }, + "scripts": { + "test": "anchor run test-with-build" + } +} diff --git a/tests/solang/solidity/flipper.sol b/tests/solang/solidity/flipper.sol new file mode 100644 index 0000000000..9931b27370 --- /dev/null +++ b/tests/solang/solidity/flipper.sol @@ -0,0 +1,22 @@ + +@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC") +contract flipper { + bool private value = true; + + @payer(payer) + constructor() { + print("Hello, World!"); + } + + /// A message that can be called on instantiated contracts. + /// This one flips the value of the stored `bool` from `true` + /// to `false` and vice versa. + function flip() public { + value = !value; + } + + /// Simply returns the current value of our `bool`. + function get() public view returns (bool) { + return value; + } +} diff --git a/tests/solang/tests/solang.ts b/tests/solang/tests/solang.ts new file mode 100644 index 0000000000..05c8f1f405 --- /dev/null +++ b/tests/solang/tests/solang.ts @@ -0,0 +1,43 @@ +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { Flipper } from "../target/types/flipper"; + +describe("flipper", () => { + // Configure the client to use the local cluster. + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + + const dataAccount = anchor.web3.Keypair.generate(); + const wallet = provider.wallet; + + const program = anchor.workspace.Flipper as Program; + + it("Is initialized!", async () => { + // Add your test here. + const tx = await program.methods + .new() + .accounts({ dataAccount: dataAccount.publicKey }) + .signers([dataAccount]) + .rpc(); + console.log("Your transaction signature", tx); + + const val1 = await program.methods + .get() + .accounts({ dataAccount: dataAccount.publicKey }) + .view(); + + console.log("state", val1); + + await program.methods + .flip() + .accounts({ dataAccount: dataAccount.publicKey }) + .rpc(); + + const val2 = await program.methods + .get() + .accounts({ dataAccount: dataAccount.publicKey }) + .view(); + + console.log("state", val2); + }); +}); diff --git a/tests/solang/tsconfig.json b/tests/solang/tsconfig.json new file mode 100644 index 0000000000..b3b6656d38 --- /dev/null +++ b/tests/solang/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true, + "skipLibCheck": true + } +}