From 5c98aa5949fcbda2af5a9dd6a00517b58e9e7892 Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Mon, 12 May 2025 16:02:21 +0300 Subject: [PATCH 1/4] feat: reproducible build --- .../anatomy/reproducible-builds.md | 41 ------------------ .../static/docs/assets/reproducible-build.png | Bin 0 -> 27819 bytes 2 files changed, 41 deletions(-) delete mode 100644 docs/smart-contracts/anatomy/reproducible-builds.md create mode 100644 website/static/docs/assets/reproducible-build.png diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md deleted file mode 100644 index d79bb719a1..0000000000 --- a/docs/smart-contracts/anatomy/reproducible-builds.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: reproducible-builds -title: Reproducible Builds ---- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -Reproducible builds let different people build the same program and get the exact same outputs as one another. It helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract user can build it themselves and check that the binaries are identical. - -## Problem - - - - -If you will build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billion other factors in your build environment. Rust community has a long story of fighting this issue but still, [it is not achieved yet](https://github.com/rust-lang/rust/labels/A-reproducibility). - -### CI solution - -We recommend you to build your contracts with the use of our [Contract Builder](https://github.com/near/near-sdk-rs/tree/master/contract-builder). It's is using Docker, controlled and sharable environment that can be used by both you and your users. Docker image is available [here](https://hub.docker.com/r/nearprotocol/contract-builder). The contract built in it will result in a binary that is the same if built on other machines. - - - - -For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. - -When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. - -### Ensuring Reproducible Python Contracts - -To ensure your Python contracts are reproducible: - -1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. - -2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. - -3. **Document Python version**: Make sure to document which Python version your contract was developed with. - -4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. - - - diff --git a/website/static/docs/assets/reproducible-build.png b/website/static/docs/assets/reproducible-build.png new file mode 100644 index 0000000000000000000000000000000000000000..1a2aaeb4afa301ea2c5e323f6c2a961c2023f155 GIT binary patch literal 27819 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 literal 0 HcmV?d00001 From c344127b5714d01366f2e0b57d649d744182d55e Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Mon, 12 May 2025 16:10:29 +0300 Subject: [PATCH 2/4] revert file name --- .../anatomy/reproducible-builds.md | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docs/smart-contracts/anatomy/reproducible-builds.md diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md new file mode 100644 index 0000000000..1f2b4c5b3d --- /dev/null +++ b/docs/smart-contracts/anatomy/reproducible-builds.md @@ -0,0 +1,112 @@ +--- +id: reproducible-builds +title: Reproducible Builds +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Reproducible builds let different people build the same program and get the exact same outputs as one another. It helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract user can build it themselves and check that the binaries are identical. + +## Problem + + + + +If you will build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billion other factors in your build environment thus, the Rust community has a long story of fighting this issue. + +To achieve reproducible builds NEAR utilizes several components such as [NEP-330-Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com) and [SourceScan](https://github.com/SourceScan). + +:::info +In order to make use of reproducible builds, you will need [Docker](https://docker.com) installed on your machine +::: + +When initializing your project with `cargo near new` the generated `Cargo.toml` will include information of the build environment and repository. + +```toml +# ... +repository = "https://github.com//" +# ... +[package.metadata.near.reproducible_build] +image = "sourcescan/cargo-near:0.13.5-rust-1.85.1" +image_digest = "sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3" +passed_env = [] +container_build_command = [ + "cargo", + "near", + "build", + "non-reproducible-wasm", + "--locked", +] +# ... +``` + +When deploying with `cargo near deploy`, this information is used to clone the repository and compile the contract in a Docker container. + +The compiling process will add method `contract_source_metadata` to the contract **with no changes to the contracts code or logic** that will return the resulted metadata. + +After the contract is deployed, we can see the metadata by calling the method `contract_source_metadata` eg. + +```zsh +near view contract_source_metadata + + INFO --- Result ------------------------- + | { + | "build_info": { + | "build_command": [ + | "cargo", + | "near", + | "build", + | "non-reproducible-wasm", + | "--locked" + | ], + | "build_environment": "sourcescan/cargo-near:0.13.5-rust-1.85.1@sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3", + | "contract_path": "", + | "output_wasm_path": null, + | "source_code_snapshot": "" + | }, + | "link": "", + | "standards": [ + | { + | "standard": "nep330", + | "version": "1.3.0" + | } + | ], + | "version": "0.1.0" + | } + | ------------------------------------ +``` + +## Verify and Publish +In order to verify and publish your contracts code we can use [NearBlocks](https://nearblocks.io) to trigger the verification process. Navigate to the contracts account page and under the **Contract** tab you will see the **Verify and Publish** button. After the verification process is completed the contract's source code along with the metadata would be publicly accessible on NearBlocks on the `Contract -> Contract Code` Tab. + +![reproducible-build](/docs/assets/reproducible-build.png) + +For a step-by-step guide on how to verify your contract, check out the [Verification Guide](https://github.com/SourceScan/verification-guide) bellow. + +## Additional Resources + +- [Verifying Smart Contracts on NEAR: Step-by-Step Guide](https://github.com/SourceScan/verification-guide) +- [Tools Community Call #10 - Introducing Reproducible Builds (video)](https://youtu.be/RBIAcQj7nFs?t=1742) + + + + + +For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. + +When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. + +### Ensuring Reproducible Python Contracts + +To ensure your Python contracts are reproducible: + +1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. + +2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. + +3. **Document Python version**: Make sure to document which Python version your contract was developed with. + +4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. + + + From 5d19d39b59813e815c77c497ebb0e93c3ddf1d5b Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Fri, 16 May 2025 15:55:21 +0300 Subject: [PATCH 3/4] fix: grammar --- .../anatomy/reproducible-builds.md | 83 ++----------------- 1 file changed, 5 insertions(+), 78 deletions(-) diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md index 1f2b4c5b3d..4f0eb9d7de 100644 --- a/docs/smart-contracts/anatomy/reproducible-builds.md +++ b/docs/smart-contracts/anatomy/reproducible-builds.md @@ -1,26 +1,25 @@ ---- id: reproducible-builds title: Reproducible Builds --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Reproducible builds let different people build the same program and get the exact same outputs as one another. It helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract user can build it themselves and check that the binaries are identical. +Reproducible builds allow different people to build the same program and produce identical outputs. This helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract, users can build it themselves and check that the binaries match exactly. ## Problem -If you will build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billion other factors in your build environment thus, the Rust community has a long story of fighting this issue. +If you build your contract on two different machines, you're likely to get two similar but not identical binaries. Your build artifact can be affected by locale, timezone, build path, and many other factors in your environment. As a result, the Rust community has a long history of addressing this issue. -To achieve reproducible builds NEAR utilizes several components such as [NEP-330-Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com) and [SourceScan](https://github.com/SourceScan). +To achieve reproducible builds, NEAR uses several components, such as [NEP-330 Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com), and [SourceScan](https://github.com/SourceScan). :::info -In order to make use of reproducible builds, you will need [Docker](https://docker.com) installed on your machine +To use reproducible builds, you need to have [Docker](https://docker.com) installed on your machine. ::: -When initializing your project with `cargo near new` the generated `Cargo.toml` will include information of the build environment and repository. +When initializing your project with `cargo near new`, the generated `Cargo.toml` will include information about the build environment and repository. ```toml # ... @@ -38,75 +37,3 @@ container_build_command = [ "--locked", ] # ... -``` - -When deploying with `cargo near deploy`, this information is used to clone the repository and compile the contract in a Docker container. - -The compiling process will add method `contract_source_metadata` to the contract **with no changes to the contracts code or logic** that will return the resulted metadata. - -After the contract is deployed, we can see the metadata by calling the method `contract_source_metadata` eg. - -```zsh -near view contract_source_metadata - - INFO --- Result ------------------------- - | { - | "build_info": { - | "build_command": [ - | "cargo", - | "near", - | "build", - | "non-reproducible-wasm", - | "--locked" - | ], - | "build_environment": "sourcescan/cargo-near:0.13.5-rust-1.85.1@sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3", - | "contract_path": "", - | "output_wasm_path": null, - | "source_code_snapshot": "" - | }, - | "link": "", - | "standards": [ - | { - | "standard": "nep330", - | "version": "1.3.0" - | } - | ], - | "version": "0.1.0" - | } - | ------------------------------------ -``` - -## Verify and Publish -In order to verify and publish your contracts code we can use [NearBlocks](https://nearblocks.io) to trigger the verification process. Navigate to the contracts account page and under the **Contract** tab you will see the **Verify and Publish** button. After the verification process is completed the contract's source code along with the metadata would be publicly accessible on NearBlocks on the `Contract -> Contract Code` Tab. - -![reproducible-build](/docs/assets/reproducible-build.png) - -For a step-by-step guide on how to verify your contract, check out the [Verification Guide](https://github.com/SourceScan/verification-guide) bellow. - -## Additional Resources - -- [Verifying Smart Contracts on NEAR: Step-by-Step Guide](https://github.com/SourceScan/verification-guide) -- [Tools Community Call #10 - Introducing Reproducible Builds (video)](https://youtu.be/RBIAcQj7nFs?t=1742) - - - - - -For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. - -When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. - -### Ensuring Reproducible Python Contracts - -To ensure your Python contracts are reproducible: - -1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. - -2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. - -3. **Document Python version**: Make sure to document which Python version your contract was developed with. - -4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. - - - From 1c293f61456d02eef5749597c9c240b338593485 Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Fri, 16 May 2025 16:13:29 +0300 Subject: [PATCH 4/4] fix --- .../anatomy/reproducible-builds.md | 81 ++++++++++++++++++- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md index 4f0eb9d7de..4d3082e12d 100644 --- a/docs/smart-contracts/anatomy/reproducible-builds.md +++ b/docs/smart-contracts/anatomy/reproducible-builds.md @@ -1,22 +1,23 @@ +--- id: reproducible-builds title: Reproducible Builds --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Reproducible builds allow different people to build the same program and produce identical outputs. This helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract, users can build it themselves and check that the binaries match exactly. +Reproducible builds let different people build the same program and get the exact same outputs as one another. They help users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract, users can build it themselves and check that the binaries are identical. ## Problem -If you build your contract on two different machines, you're likely to get two similar but not identical binaries. Your build artifact can be affected by locale, timezone, build path, and many other factors in your environment. As a result, the Rust community has a long history of addressing this issue. +If you build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billions of other factors in your build environment. Thus, the Rust community has a long history of addressing this issue. -To achieve reproducible builds, NEAR uses several components, such as [NEP-330 Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com), and [SourceScan](https://github.com/SourceScan). +To achieve reproducible builds, NEAR utilizes several components such as [NEP-330-Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com), and [SourceScan](https://github.com/SourceScan). :::info -To use reproducible builds, you need to have [Docker](https://docker.com) installed on your machine. +In order to make use of reproducible builds, you will need [Docker](https://docker.com) installed on your machine. ::: When initializing your project with `cargo near new`, the generated `Cargo.toml` will include information about the build environment and repository. @@ -37,3 +38,75 @@ container_build_command = [ "--locked", ] # ... +``` + +When deploying with `cargo near deploy`, this information is used to clone the repository and compile the contract in a Docker container. + +The compiling process will add the method `contract_source_metadata` to the contract **with no changes to the contract's code or logic** that will return the resulting metadata. + +After the contract is deployed, we can see the metadata by calling the method `contract_source_metadata`, e.g.: + +```zsh +near view contract_source_metadata + + INFO --- Result ------------------------- + | { + | "build_info": { + | "build_command": [ + | "cargo", + | "near", + | "build", + | "non-reproducible-wasm", + | "--locked" + | ], + | "build_environment": "sourcescan/cargo-near:0.13.5-rust-1.85.1@sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3", + | "contract_path": "", + | "output_wasm_path": null, + | "source_code_snapshot": "" + | }, + | "link": "", + | "standards": [ + | { + | "standard": "nep330", + | "version": "1.3.0" + | } + | ], + | "version": "0.1.0" + | } + | ------------------------------------ +``` + +## Verify and Publish +In order to verify and publish your contract's code, we can use [NearBlocks](https://nearblocks.io) to trigger the verification process. Navigate to the contract's account page and under the **Contract** tab, you will see the **Verify and Publish** button. After the verification process is completed, the contract's source code along with the metadata will be publicly accessible on NearBlocks on the `Contract -> Contract Code` tab. + +![reproducible-build](/docs/assets/reproducible-build.png) + +For a step-by-step guide on how to verify your contract, check out the [Verification Guide](https://github.com/SourceScan/verification-guide). + +## Additional Resources + +- [Verifying Smart Contracts on NEAR: Step-by-Step Guide](https://github.com/SourceScan/verification-guide) +- [Tools Community Call #10 - Introducing Reproducible Builds (video)](https://youtu.be/RBIAcQj7nFs?t=1742) + + + + + +For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. + +When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. + +### Ensuring Reproducible Python Contracts + +To ensure your Python contracts are reproducible: + +1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. + +2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. + +3. **Document Python version**: Make sure to document which Python version your contract was developed with. + +4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. + + + \ No newline at end of file