Setting up a Build Pipeline with Docker and Hardhat
TL;DR Ensure your AWS pipeline buildspec.yaml runs a hardhat compile
to provide your runtime with the ABI artifacts.
Running Web apps in Docker has become the generally accepted enterprise-grade solution. Through Docker, we exercise a great deal more control over the runtime environment, allowing maximum portability for our code. Ethereum web apps - aka Dapps - are no exception. Typically, we will create a build pipeline that responds to each code push, building a new Docker image from the new codebase.
JavaScript is the most common language used in Dapps, enabling developers to profit from frameworks like Hardhat to aid the development process. There are also mature, open-source libraries like Ethers.js for managing the interaction between JavaScript apps and the blockchain.
Local compilation
The Ethereum Virtual Machine (EVM) uses Bytecode, not a high-level programming language. As such, JavaScript needs an Application Binary Interface, or ABI, to know what methods a contract exposes to the outside world. ABIs and other files facilitating this translation from JS to Bytecode are commonly known as Artifacts.
Hardhat enables us to create Artifacts very simply. After having put your contracts in a folder called Contracts at the root of your repo, just run:
This command will create a folder called artifacts
at the root. This folder is essential for the execution of the App, so it is a critical thing to include when we’re building the Docker image. We need to have these files when we run our build pipeline.
Dockerfile
We list the instructions to build and run our Docker image in our Dockerfile. The two dots mean ‘copy all files from root to the root inside the container’:
So, when we run the docker build command, we need the Artifacts to be at the root of wherever the Build pipeline is accessing our repo.
gitignore
Like most frameworks, when you initialise your project Hardhat creates a .gitignore
file for you. This .gitignore stops sensitive files from going into your repo, including your artifacts
. Check the bottom of the standard Hardhat gitignore:
At your Build pipeline runtime, you won’t have these folders in your remote repo. The pipeline will need these as part of the build. It will fail when it doesn’t find them. We can either remove the reference to them in gitignore (not advised) or ensure our pipeline builds them as part of its execution.
buildspec.yaml
The buildspec.yaml file tells your AWS build pipeline what steps to execute. Here, we need to instruct the build agent to run our hardhat compilation and create the artifacts
folder.
In our pre_build
phase, we must first ensure we have Hardhat in the runtime, which we do via npm install
. We can execute our npx hardhat compile
following this step, ensuring the contract ABIs are present.
Quick gotcha: the below buildspec.yaml won’t work unless you specify the AWS_ACCOUNT_ID
as an environment variable. Not sure why this isn’t a default variable in CodeBuild/CodePipeline like AWS_DEFAULT_REGION
is, but there you go.