Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ contracts/@openzeppelin/*
evmd/build/

build/

.testnets
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,25 @@ contracts-compile:
contracts-add:
@echo "Adding a new smart contract to be compiled..."
@python3 ./scripts/compile_smart_contracts/compile_smart_contracts.py --add $(CONTRACT)

###############################################################################
### Localnet ###
###############################################################################

localnet-build-env:
$(MAKE) -C contrib/images evmd-env

localnet-build-nodes:
$(DOCKER) run --rm -v $(CURDIR)/.testnets:/data cosmos/evmd \
testnet init-files --v 4 -o /data --starting-ip-address 192.168.10.2 --keyring-backend=test --chain-id=local-4221 --use-docker=true
docker compose up -d

localnet-stop:
docker compose down

# localnet-start will run a 4-node testnet locally. The nodes are
# based off the docker images in: ./contrib/images/simd-env
localnet-start: localnet-stop localnet-build-env localnet-build-nodes


.PHONY: localnet-start localnet-stop localnet-build-env localnet-build-nodes
10 changes: 10 additions & 0 deletions contrib/images/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
all: evmd-env

evmd-env: evmd-rmi
docker build --tag cosmos/evmd -f evmd-env/Dockerfile \
$(shell git rev-parse --show-toplevel)

evmd-rmi:
docker rmi cosmos/evmd 2>/dev/null; true

.PHONY: all evmd-env evmd-rmi
42 changes: 42 additions & 0 deletions contrib/images/evmd-env/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Info on how to use this docker image can be found in DOCKER_README.md
ARG IMG_TAG=latest

# Compile the evmd binary
FROM golang:1.24-alpine AS evmd-builder
WORKDIR /work
ENV PACKAGES="curl build-base git bash file linux-headers eudev-dev"
RUN apk add --no-cache $PACKAGES

COPY go.mod go.sum* ./
RUN go mod download

COPY . .
RUN LEDGER_ENABLED=false COSMOS_BUILD_OPTIONS="staticlink" BUILD_TAGS=muslc make build
RUN echo "Checking binary linkage..." \
&& file /work/build/evmd \
&& (file /work/build/evmd | grep -q "statically linked" || echo "Warning: Binary may not be statically linked")

FROM alpine:$IMG_TAG AS run
RUN apk add --no-cache build-base jq bash curl
RUN addgroup -g 1025 nonroot
RUN adduser -D nonroot -u 1025 -G nonroot

# Set up the runtime environment
EXPOSE 26656 26657 1317 9090
STOPSIGNAL SIGTERM
VOLUME /evmd
WORKDIR /evmd

# Copy the wrapper script and binary to expected locations
COPY contrib/images/evmd-env/wrapper.sh /usr/bin/wrapper.sh
COPY --from=evmd-builder /work/build/evmd /evmd/
COPY --from=evmd-builder /work/build/evmd /usr/local/bin/

# Set proper ownership and permissions before switching to nonroot user
RUN chown nonroot:nonroot /usr/bin/wrapper.sh && chmod +x /usr/bin/wrapper.sh
RUN chown -R nonroot:nonroot /evmd

USER nonroot

ENTRYPOINT ["/usr/bin/wrapper.sh"]
CMD ["start", "--log_format", "plain", "--minimum-gas-prices", "0.0001atest", "--json-rpc.api", "eth,txpool,personal,net,debug,web3", "--chain-id", "local-4221"]
19 changes: 19 additions & 0 deletions contrib/images/evmd-env/wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env sh
set -x

BINARY=/evmd/${BINARY:-evmd}
ID=${ID:-0}
LOG=${LOG:-evmd.log}

if ! [ -f "${BINARY}" ]; then
echo "The binary $(basename "${BINARY}") cannot be found. Please add the binary to the shared folder. Please use the BINARY environment variable if the name of the binary is not 'evmd'"
exit 1
fi

export EVMDHOME="/data/node${ID}/evmd"

if [ -d "$(dirname "${EVMDHOME}"/"${LOG}")" ]; then
"${BINARY}" --home "${EVMDHOME}" "$@" | tee "${EVMDHOME}/${LOG}"
else
"${BINARY}" --home "${EVMDHOME}" "$@"
fi
106 changes: 106 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
version: "3"

services:
evmdnode0:
container_name: evmdnode0
image: "cosmos/evmd"
environment:
- DEBUG=0
- ID=0
- LOG=${LOG:-evmd.log}
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
ports:
- "26656-26657:26656-26657"
- "1317:1317"
- "9090:9090"
- "2345:2345"
- "6065:6065"
- "8545-8546:8545-8546"
volumes:
- ./.testnets:/data:Z
networks:
localnet:
ipv4_address: 192.168.10.2

evmdnode1:
container_name: evmdnode1
image: "cosmos/evmd"
environment:
- DEBUG=0
- ID=1
- LOG=${LOG:-evmd.log}
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
ports:
- "26666-26667:26656-26657"
- "1318:1317"
- "9091:9090"
- "2346:2345"
- "6075:6065"
- "8555-8556:8545-8546"
volumes:
- ./.testnets:/data:Z
networks:
localnet:
ipv4_address: 192.168.10.3

evmdnode2:
container_name: evmdnode2
image: "cosmos/evmd"
environment:
- DEBUG=0
- ID=2
- LOG=${LOG:-evmd.log}
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
ports:
- "26676-26677:26656-26657"
- "1319:1317"
- "9092:9090"
- "2347:2345"
- "6085:6065"
- "8565-8566:8545-8546"
volumes:
- ./.testnets:/data:Z
networks:
localnet:
ipv4_address: 192.168.10.4

evmdnode3:
container_name: evmdnode3
image: "cosmos/evmd"
environment:
- DEBUG=0
- ID=3
- LOG=${LOG:-evmd.log}
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
ports:
- "26686-26687:26656-26657"
- "1320:1317"
- "9093:9090"
- "2348:2345"
- "6095:6065"
- "8575-8576:8545-8546"
volumes:
- ./.testnets:/data:Z
networks:
localnet:
ipv4_address: 192.168.10.5

networks:
localnet:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.10.0/25
151 changes: 151 additions & 0 deletions evmd/cmd/evmd/cmd/creator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package cmd

import (
"errors"
"io"
"path/filepath"

dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/cosmos/evm/evmd"
evmdconfig "github.com/cosmos/evm/evmd/cmd/evmd/config"
"github.com/spf13/cast"
"github.com/spf13/viper"

"cosmossdk.io/log"
"cosmossdk.io/store"
"cosmossdk.io/store/snapshots"
snapshottypes "cosmossdk.io/store/snapshots/types"
storetypes "cosmossdk.io/store/types"
)

type appCreator struct{}

func (a appCreator) newApp(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
appOpts servertypes.AppOptions,
) servertypes.Application {
var cache storetypes.MultiStorePersistentCache
if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) {
cache = store.NewCommitKVStoreCacheManager()
}
pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts)
if err != nil {
panic(err)
}

skipUpgradeHeights := make(map[int64]bool)
for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) {
skipUpgradeHeights[int64(h)] = true
}

homeDir := cast.ToString(appOpts.Get(flags.FlagHome))
chainID := cast.ToString(appOpts.Get(flags.FlagChainID))
if chainID == "" {
// fallback to genesis chain-id
genDocFile := filepath.Join(homeDir, cast.ToString(appOpts.Get("genesis_file")))
appGenesis, err := genutiltypes.AppGenesisFromFile(genDocFile)
if err != nil {
panic(err)
}

chainID = appGenesis.ChainID
}

snapshotDir := filepath.Join(homeDir, "data", "snapshots")
snapshotDB, err := dbm.NewDB("metadata", server.GetAppDBBackend(appOpts), snapshotDir)
if err != nil {
panic(err)
}
snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir)
if err != nil {
panic(err)
}

// BaseApp Opts
snapshotOptions := snapshottypes.NewSnapshotOptions(
cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)),
cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)),
)
baseappOptions := []func(*baseapp.BaseApp){
baseapp.SetChainID(chainID),
baseapp.SetPruning(pruningOpts),
baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))),
baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))),
baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))),
baseapp.SetInterBlockCache(cache),
baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))),
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))),
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))),
}

return evmd.NewExampleApp(
logger,
db,
traceStore,
true,
simtestutil.EmptyAppOptions{},
evmdconfig.EVMChainID,
evmdconfig.EvmAppOptions,
baseappOptions...,
)
}

func (a appCreator) appExport(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
height int64,
forZeroHeight bool,
jailAllowedAddrs []string,
appOpts servertypes.AppOptions,
modulesToExport []string,
) (servertypes.ExportedApp, error) {
var evmApp *evmd.EVMD

homePath, ok := appOpts.Get(flags.FlagHome).(string)
if !ok || homePath == "" {
return servertypes.ExportedApp{}, errors.New("application home is not set")
}

// InvCheckPeriod
viperAppOpts, ok := appOpts.(*viper.Viper)
if !ok {
return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
}
// overwrite the FlagInvCheckPeriod
viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
appOpts = viperAppOpts

var loadLatest bool
if height == -1 {
loadLatest = true
}

evmApp = evmd.NewExampleApp(
logger,
db,
traceStore,
loadLatest,
appOpts,
evmdconfig.EVMChainID,
evmdconfig.EvmAppOptions,
)

if height != -1 {
if err := evmApp.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
}

return evmApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
}
Loading
Loading