Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 55 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,73 @@
FROM golang:1.23.6 AS builder
# ---------------------------------------------------------------------------
# Stage 1: Fetch configs
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM golang:1.23.6-bookworm AS config-fetcher


WORKDIR /multiversx
WORKDIR /src
COPY . .

RUN go mod tidy
WORKDIR /src/cmd/chainsimulator
RUN go build -o chainsimulator \
&& ./chainsimulator --fetch-configs-and-close

WORKDIR /multiversx/cmd/chainsimulator
# ---------------------------------------------------------------------------
# Stage 2: Build the binary + extract Wasmer libs
# ---------------------------------------------------------------------------
FROM golang:1.23.6-bookworm AS builder

RUN go build -o chainsimulator
WORKDIR /src
COPY . .

RUN mkdir -p /lib_amd64 /lib_arm64
# Download all modules
RUN go mod download

RUN cp /go/pkg/mod/github.com/multiversx/$(cat /multiversx/go.sum | grep mx-chain-vm-v | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer/libwasmer_linux_amd64.so /lib_amd64/
RUN cp /go/pkg/mod/github.com/multiversx/$(cat /multiversx/go.sum | grep mx-chain-vm-go | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer2/libvmexeccapi.so /lib_amd64/
WORKDIR /src/cmd/chainsimulator

RUN cp /go/pkg/mod/github.com/multiversx/$(cat /multiversx/go.sum | grep mx-chain-vm-v | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer/libwasmer_linux_arm64_shim.so /lib_arm64/
RUN cp /go/pkg/mod/github.com/multiversx/$(cat /multiversx/go.sum | grep mx-chain-vm-go | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer2/libvmexeccapi_arm.so /lib_arm64/
# Build with optimizations: strip debug symbols, smaller binary
# CGO_ENABLED=1 is implicit and required by Wasmer bindings.
RUN go build \
-ldflags="-s -w" \
-trimpath \
-o /out/chainsimulator

# ---------------------------------------------------------------------------
# Extract architecture-specific Wasmer shared libraries
# ---------------------------------------------------------------------------
RUN mkdir -p /out/lib

FROM ubuntu:22.04
ARG TARGETARCH
RUN apt-get update && apt-get install -y git curl
RUN cp /go/pkg/mod/github.com/multiversx/$(cat /src/go.sum \
| grep mx-chain-vm-v | sort -n | tail -n -1 \
| awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer/libwasmer_linux_$(dpkg --print-architecture | sed 's/arm64/arm64_shim/').so \
/out/lib/ 2>/dev/null || true

COPY --from=builder /multiversx/cmd/chainsimulator /multiversx
RUN cp /go/pkg/mod/github.com/multiversx/$(cat /src/go.sum \
| grep mx-chain-vm-go | sort -n | tail -n -1 \
| awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer2/libvmexeccapi$(dpkg --print-architecture | sed 's/amd64//;s/arm64/_arm/').so \
/out/lib/ 2>/dev/null || true

EXPOSE 8085
# ---------------------------------------------------------------------------
# Stage 3: Minimal runtime image (distroless)
# ---------------------------------------------------------------------------
FROM gcr.io/distroless/cc-debian13:nonroot

WORKDIR /multiversx
LABEL org.opencontainers.image.title="mx-chain-simulator-go" \
org.opencontainers.image.description="MultiversX Chain Simulator" \
org.opencontainers.image.source="https://github.com/multiversx/mx-chain-simulator-go" \
org.opencontainers.image.licenses="GPL-3.0"

# Copy architecture-specific files
COPY --from=builder "/lib_${TARGETARCH}/*" "/lib/"
# Copy binary
COPY --from=builder --chown=nonroot:nonroot /out/chainsimulator /app/chainsimulator

CMD ["/bin/bash"]
# Copy pre-fetched configs
COPY --from=config-fetcher --chown=nonroot:nonroot /src/cmd/chainsimulator/config /app/config

ENTRYPOINT ["./chainsimulator"]
# Copy Wasmer libs
COPY --from=builder /out/lib/ /lib/

WORKDIR /app
EXPOSE 8085

# Run as non-root for security (UID 65532 is "nonroot" in distroless)
USER nonroot:nonroot

ENTRYPOINT ["./chainsimulator"]
116 changes: 99 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,41 +1,123 @@
CHAIN_SIMULATOR_IMAGE_NAME=chainsimulator
CHAIN_SIMULATOR_IMAGE_TAG=latest
DOCKER_FILE=Dockerfile
IMAGE_NAME=simulator_image
IMAGE_NAME ?= chainsimulator
IMAGE_TAG ?= latest
REGISTRY ?= multiversx
DOCKER_FILE ?= Dockerfile
PLATFORMS ?= linux/amd64,linux/arm64
CONTAINER_NAME ?= simulator_instance
FULL_IMAGE = $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)

## Build the Go binary locally
.PHONY: build
build:
cd cmd/chainsimulator && go build -ldflags="-s -w" -trimpath -o chainsimulator

## Fetch configs locally
.PHONY: fetch-configs
fetch-configs: build
cd cmd/chainsimulator && ./chainsimulator --fetch-configs-and-close

## Build Docker image (single arch, current platform)
.PHONY: docker-build
docker-build:
docker build \
-t ${CHAIN_SIMULATOR_IMAGE_NAME}:${CHAIN_SIMULATOR_IMAGE_TAG} \
-f ${DOCKER_FILE} \
.
DOCKER_BUILDKIT=1 docker build \
-t $(FULL_IMAGE) \
-f $(DOCKER_FILE) \
.

run-faucet-test:
$(MAKE) docker-build
docker run -d --name "${IMAGE_NAME}" -p 8085:8085 ${CHAIN_SIMULATOR_IMAGE_NAME}:${CHAIN_SIMULATOR_IMAGE_TAG}
## Build multi-arch image and push to registry (requires login)
## This is the correct way to produce a multi-platform manifest.
.PHONY: docker-build-push
docker-build-push:
docker buildx build \
--platform $(PLATFORMS) \
-t $(FULL_IMAGE) \
-f $(DOCKER_FILE) \
--push \
.

## Register QEMU for cross-platform builds (run once per boot)
.PHONY: qemu-setup
qemu-setup:
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

## Run the simulator container
.PHONY: docker-run
docker-run:
docker run -d \
--name "$(CONTAINER_NAME)" \
--read-only \
--tmpfs /tmp \
-p 8085:8085 \
$(FULL_IMAGE)

## Stop and remove the simulator container
.PHONY: docker-stop
docker-stop:
docker stop "$(CONTAINER_NAME)" 2>/dev/null || true
docker rm "$(CONTAINER_NAME)" 2>/dev/null || true

## Run faucet example test
.PHONY: run-faucet-test
run-faucet-test: docker-build
docker run -d --name "$(CONTAINER_NAME)" -p 8085:8085 $(FULL_IMAGE)
sleep 2s
cd examples/faucet && /bin/bash faucet.sh
docker stop "${IMAGE_NAME}"
docker rm ${IMAGE_NAME} 2> /dev/null
$(MAKE) docker-stop

## Run all examples
.PHONY: run-examples
run-examples:
printf '%s\n' '{ File = "enableEpochs.toml", Path = "EnableEpochs.StakeLimitsEnableEpoch", Value = 1000000 },' > temp.txt
sed -i '4r temp.txt' cmd/chainsimulator/config/nodeOverrideDefault.toml
rm temp.txt

$(MAKE) docker-build
docker run -d --name "${IMAGE_NAME}" -p 8085:8085 ${CHAIN_SIMULATOR_IMAGE_NAME}:${CHAIN_SIMULATOR_IMAGE_TAG}
docker run -d --name "$(CONTAINER_NAME)" -p 8085:8085 $(FULL_IMAGE)
cd scripts/run-examples && /bin/bash install-python-deps.sh && /bin/bash script.sh
docker stop "${IMAGE_NAME}"
docker rm ${IMAGE_NAME}
$(MAKE) docker-stop

## Install golint if not already present
.PHONY: lint-install
lint-install:
ifeq (,$(wildcard test -f bin/golangci-lint))
@echo "Installing golint"
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s
endif

## Run golint on the codebase
.PHONY: run-lint
run-lint:
@echo "Running golint"
bin/golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 --timeout=2m

## Run lint installation and then the linter
.PHONY: lint
lint: lint-install run-lint

## Show image details
.PHONY: docker-info
docker-info:
@echo "Image: $(FULL_IMAGE)"
@echo "Dockerfile: $(DOCKER_FILE)"
@echo "Platforms: $(PLATFORMS)"
@docker images $(FULL_IMAGE) --format "Size: {{.Size}}"

## Run security scan with trivy (if installed)
.PHONY: docker-scan
docker-scan:
trivy image --severity HIGH,CRITICAL $(FULL_IMAGE)

## Show available targets
.PHONY: help
help:
@echo "Available targets:"
@echo " build Build Go binary locally"
@echo " fetch-configs Fetch configs from GitHub repos"
@echo " docker-build Build Docker image (current platform, docker build)"
@echo " docker-build-push Build & push multi-arch image to registry"
@echo " qemu-setup Register QEMU for cross-arch builds"
@echo " docker-run Run the simulator container (read-only)"
@echo " docker-stop Stop and remove container"
@echo " docker-info Show image details"
@echo " docker-scan Trivy security scan"
@echo " lint Run linter"
@echo " help Show this help"
41 changes: 36 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,10 @@ This endpoint resets (clears) an internal cache used by the `/validator/statisti

Before proceeding, ensure you have the following prerequisites:

- Go programming environment set up.
- Go 1.23.x programming environment set up.
- Git installed.
- Docker with BuildKit support (for container builds).
- Docker Buildx (for multi-arch builds).


## Install
Expand All @@ -431,6 +433,11 @@ Using the `cmd/chainsimulator` package as root, execute the following commands:
- install go dependencies: `go install`
- build executable: `go build -o chainsimulator`

Alternatively, use the Makefile:
```
make build
```

Note: go version 1.23.* should be used to build the executable.


Expand Down Expand Up @@ -513,14 +520,38 @@ INFO [2024-04-18 10:48:47.231] chain simulator's is accessible through the URL
```


### Build docker image
### Docker

The Docker image uses a multi-stage build with a [distroless](https://github.com/GoogleContainerTools/distroless) runtime image (`gcr.io/distroless/cc-debian13`). The container runs as a non-root user (UID 65532) for security. Configs are pre-fetched at build time so `git` and `curl` are not required at runtime.

#### Build (single arch, current platform)
```
make docker-build
```

#### Build & push multi-arch (amd64 + arm64)
```
make docker-build-push
```

For cross-platform builds from an amd64 host, register QEMU first (once per boot):
```
make qemu-setup
```

#### Run
```
make docker-run
```

The container is started in read-only mode with a tmpfs on `/tmp`. To pass extra flags:
```
DOCKER_BUILDKIT=1 docker build -t chainsimulator:latest .
docker run -p 8085:8085 multiversx/chainsimulator:latest --log-level *:DEBUG
```

### Run with docker
#### Available Makefile targets
```
docker run -p 8085:8085 chainsimulator:latest --log-level *:DEBUG
make help
```

### Enable `HostDriver`
Expand Down