diff --git a/clients/opgeth/Dockerfile b/clients/opgeth/Dockerfile new file mode 100644 index 0000000000..66e303b17b --- /dev/null +++ b/clients/opgeth/Dockerfile @@ -0,0 +1,53 @@ +# Docker container spec for building the master branch of go-ethereum. +# +# The build process it potentially longer running but every effort was made to +# produce a very minimalistic container that can be reused many times without +# needing to constantly rebuild. + +ARG branch=latest +FROM javedop/opgeth:$branch + +RUN apk add --update bash curl jq + +# FROM alpine:latest +# ARG branch=master + +# Build go-ethereum on the fly and delete all build tools afterwards +# RUN \ +# apk add --update bash curl jq go git make gcc musl-dev \ +# ca-certificates linux-headers && \ +# git clone --depth 1 --branch $branch https://github.com/ethereum/go-ethereum && \ +# (cd go-ethereum && make geth) && \ +# (cd go-ethereum && \ +# echo "{}" \ +# | jq ".+ {\"repo\":\"$(git config --get remote.origin.url)\"}" \ +# | jq ".+ {\"branch\":\"$(git rev-parse --abbrev-ref HEAD)\"}" \ +# | jq ".+ {\"commit\":\"$(git rev-parse HEAD)\"}" \ +# > /version.json) && \ +# cp go-ethereum/build/bin/geth /geth && \ +# apk del go git make gcc musl-dev linux-headers && \ +# rm -rf /go-ethereum && rm -rf /var/cache/apk/* + +RUN /usr/local/bin/geth console --exec 'console.log(admin.nodeInfo.name)' --maxpeers=0 --nodiscover --dev 2>/dev/null | head -1 > /version.txt + +# Inject the startup script +ADD geth.sh /geth.sh +ADD mapper.jq /mapper.jq +RUN chmod +x /geth.sh + +# Inject the enode id retriever script +RUN mkdir /hive-bin +ADD enode.sh /hive-bin/enode.sh +RUN chmod +x /hive-bin/enode.sh + +ADD genesis.json /genesis.json + +# Export the usual networking ports to allow outside access to the node +EXPOSE 8545 8546 8547 30303 30303/udp + +# Generate the ethash verification caches +RUN \ + /usr/local/bin/geth makecache 1 ~/.ethereum/geth/ethash && \ + /usr/local/bin/geth makecache 30001 ~/.ethereum/geth/ethash + +ENTRYPOINT ["/geth.sh"] diff --git a/clients/opgeth/enode.sh b/clients/opgeth/enode.sh new file mode 100644 index 0000000000..fa715d3296 --- /dev/null +++ b/clients/opgeth/enode.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Script to retrieve the enode +# +# This is copied into the validator container by Hive +# and used to provide a client-specific enode id retriever +# + +# Immediately abort the script on any error encountered +set -e + + +TARGET_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"admin_nodeInfo","params":[],"id":1}' "localhost:8545" ) + + +TARGET_ENODE=$(echo ${TARGET_RESPONSE}| jq -r '.result.enode') +echo "$TARGET_ENODE" \ No newline at end of file diff --git a/clients/opgeth/genesis.json b/clients/opgeth/genesis.json new file mode 100644 index 0000000000..7ca6f39f73 --- /dev/null +++ b/clients/opgeth/genesis.json @@ -0,0 +1,15 @@ +{ + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x42", + "gasLimit" : "0x2fefd8", + "mixHash" : "0x2c85bcbce56429100b2108254bb56906257582aeafcbd682bc9af67a9f5aee46", + "nonce" : "0x78cc16f7b4f65485", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp" : "0x54c98c81", + "alloc" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance" : "0x09184e72a000" + } + } +} diff --git a/clients/opgeth/geth.sh b/clients/opgeth/geth.sh new file mode 100644 index 0000000000..c7725403c3 --- /dev/null +++ b/clients/opgeth/geth.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +# Startup script to initialize and boot a go-ethereum instance. +# +# This script assumes the following files: +# - `geth` binary is located in the filesystem root +# - `genesis.json` file is located in the filesystem root (mandatory) +# - `chain.rlp` file is located in the filesystem root (optional) +# - `blocks` folder is located in the filesystem root (optional) +# - `keys` folder is located in the filesystem root (optional) +# +# This script assumes the following environment variables: +# +# - HIVE_BOOTNODE enode URL of the remote bootstrap node +# - HIVE_NETWORK_ID network ID number to use for the eth protocol +# - HIVE_TESTNET whether testnet nonces (2^20) are needed +# - HIVE_NODETYPE sync and pruning selector (archive, full, light) +# +# Forks: +# +# - HIVE_FORK_HOMESTEAD block number of the homestead hard-fork transition +# - HIVE_FORK_DAO_BLOCK block number of the DAO hard-fork transition +# - HIVE_FORK_DAO_VOTE whether the node support (or opposes) the DAO fork +# - HIVE_FORK_TANGERINE block number of Tangerine Whistle transition +# - HIVE_FORK_SPURIOUS block number of Spurious Dragon transition +# - HIVE_FORK_BYZANTIUM block number for Byzantium transition +# - HIVE_FORK_CONSTANTINOPLE block number for Constantinople transition +# - HIVE_FORK_PETERSBURG block number for ConstantinopleFix/PetersBurg transition +# - HIVE_FORK_ISTANBUL block number for Istanbul transition +# - HIVE_FORK_MUIRGLACIER block number for Muir Glacier transition +# - HIVE_FORK_BERLIN block number for Berlin transition +# - HIVE_FORK_LONDON block number for London +# +# Clique PoA: +# +# - HIVE_CLIQUE_PERIOD enables clique support. value is block time in seconds. +# - HIVE_CLIQUE_PRIVATEKEY private key for clique mining +# +# Other: +# +# - HIVE_MINER enable mining. value is coinbase address. +# - HIVE_MINER_EXTRA extra-data field to set for newly minted blocks +# - HIVE_SKIP_POW if set, skip PoW verification during block import +# - HIVE_LOGLEVEL client loglevel (0-5) +# - HIVE_GRAPHQL_ENABLED enables graphql on port 8545 +# - HIVE_LES_SERVER set to '1' to enable LES server + +# Immediately abort the script on any error encountered +set -e + +geth=/usr/local/bin/geth +FLAGS="--pcscdpath=\"\"" + +if [ "$HIVE_LOGLEVEL" != "" ]; then + FLAGS="$FLAGS --verbosity=$HIVE_LOGLEVEL" +fi + +# It doesn't make sense to dial out, use only a pre-set bootnode. +FLAGS="$FLAGS --bootnodes=$HIVE_BOOTNODE" + +if [ "$HIVE_SKIP_POW" != "" ]; then + FLAGS="$FLAGS --fakepow" +fi + +# If a specific network ID is requested, use that +if [ "$HIVE_NETWORK_ID" != "" ]; then + FLAGS="$FLAGS --networkid $HIVE_NETWORK_ID" +else + # Unless otherwise specified by hive, we try to avoid mainnet networkid. If geth detects mainnet network id, + # then it tries to bump memory quite a lot + FLAGS="$FLAGS --networkid 1337" +fi + +# If the client is to be run in testnet mode, flag it as such +if [ "$HIVE_TESTNET" == "1" ]; then + FLAGS="$FLAGS --testnet" +fi + +# Handle any client mode or operation requests +if [ "$HIVE_NODETYPE" == "archive" ]; then + FLAGS="$FLAGS --syncmode full --gcmode archive" +fi +if [ "$HIVE_NODETYPE" == "full" ]; then + FLAGS="$FLAGS --syncmode snap" +fi +if [ "$HIVE_NODETYPE" == "light" ]; then + FLAGS="$FLAGS --syncmode light" +fi + +# Configure the chain. +mv /genesis.json /genesis-input.json +jq -f /mapper.jq /genesis-input.json > /genesis.json + +# Dump genesis +echo "Supplied genesis state:" +cat /genesis.json + +# Initialize the local testchain with the genesis state +echo "Initializing database with genesis state..." +$geth $FLAGS init /genesis.json + +# Don't immediately abort, some imports are meant to fail +set +e + +# Load the test chain if present +echo "Loading initial blockchain..." +if [ -f /chain.rlp ]; then + $geth $FLAGS --gcmode=archive import /chain.rlp +else + echo "Warning: chain.rlp not found." +fi + +# Load the remainder of the test chain +echo "Loading remaining individual blocks..." +if [ -d /blocks ]; then + (cd /blocks && $geth $FLAGS --gcmode=archive --verbosity=$HIVE_LOGLEVEL --nocompaction import `ls | sort -n`) +else + echo "Warning: blocks folder not found." +fi + +set -e + +# Import clique signing key. +if [ "$HIVE_CLIQUE_PRIVATEKEY" != "" ]; then + # Create password file. + echo "Importing clique key..." + echo "secret" > /geth-password-file.txt + $geth --nousb account import --password /geth-password-file.txt <(echo "$HIVE_CLIQUE_PRIVATEKEY") + + # Ensure password file is used when running geth in mining mode. + if [ "$HIVE_MINER" != "" ]; then + FLAGS="$FLAGS --password /geth-password-file.txt --unlock $HIVE_MINER --allow-insecure-unlock" + fi +fi + +# Configure any mining operation +if [ "$HIVE_MINER" != "" ] && [ "$HIVE_NODETYPE" != "light" ]; then + FLAGS="$FLAGS --mine --miner.threads 1 --miner.etherbase $HIVE_MINER" +fi +if [ "$HIVE_MINER_EXTRA" != "" ]; then + FLAGS="$FLAGS --miner.extradata $HIVE_MINER_EXTRA" +fi +FLAGS="$FLAGS --miner.gasprice 16000000000" + +# Configure LES. +if [ "$HIVE_LES_SERVER" == "1" ]; then + FLAGS="$FLAGS --light.serve 50 --light.nosyncserve" +fi + +# Configure RPC. +FLAGS="$FLAGS --http --http.addr=0.0.0.0 --http.port=8545 --http.api=admin,debug,eth,miner,net,personal,txpool,web3" +FLAGS="$FLAGS --ws --ws.addr=0.0.0.0 --ws.origins \"*\" --ws.api=admin,debug,eth,miner,net,personal,txpool,web3" + +if [ "$HIVE_TERMINAL_TOTAL_DIFFICULTY" != "" ]; then + echo "0x7365637265747365637265747365637265747365637265747365637265747365" > /jwtsecret + FLAGS="$FLAGS --authrpc.host=0.0.0.0 --authrpc.port=8550 --authrpc.jwtsecret /jwtsecret" +fi + +# Configure GraphQL. +if [ "$HIVE_GRAPHQL_ENABLED" != "" ]; then + FLAGS="$FLAGS --graphql" +fi +# used for the graphql to allow submission of unprotected tx +if [ "$HIVE_ALLOW_UNPROTECTED_TX" != "" ]; then + FLAGS="$FLAGS --rpc.allow-unprotected-txs" +fi + +# Run the go-ethereum implementation with the requested flags. +FLAGS="$FLAGS --nat=none" +echo "Running go-ethereum with flags $FLAGS" +$geth $FLAGS diff --git a/clients/opgeth/hive.yaml b/clients/opgeth/hive.yaml new file mode 100644 index 0000000000..d65baaf76f --- /dev/null +++ b/clients/opgeth/hive.yaml @@ -0,0 +1,4 @@ +roles: + - "eth1" + - "eth1_les_client" + - "eth1_les_server" diff --git a/clients/opgeth/mapper.jq b/clients/opgeth/mapper.jq new file mode 100644 index 0000000000..0cabd5795f --- /dev/null +++ b/clients/opgeth/mapper.jq @@ -0,0 +1,56 @@ +# Removes all empty keys and values in input. +def remove_empty: + . | walk( + if type == "object" then + with_entries( + select( + .value != null and + .value != "" and + .value != [] and + .key != null and + .key != "" + ) + ) + else . + end + ) +; + +# Converts decimal string to number. +def to_int: + if . == null then . else .|tonumber end +; + +# Converts "1" / "0" to boolean. +def to_bool: + if . == null then . else + if . == "1" then true else false end + end +; + +# Replace config in input. +. + { + "config": { + "ethash": (if env.HIVE_CLIQUE_PERIOD then null else {} end), + "clique": (if env.HIVE_CLIQUE_PERIOD == null then null else { + "period": env.HIVE_CLIQUE_PERIOD|to_int, + } end), + "chainId": env.HIVE_CHAIN_ID|to_int, + "homesteadBlock": env.HIVE_FORK_HOMESTEAD|to_int, + "daoForkBlock": env.HIVE_FORK_DAO_BLOCK|to_int, + "daoForkSupport": env.HIVE_FORK_DAO_VOTE|to_bool, + "eip150Block": env.HIVE_FORK_TANGERINE|to_int, + "eip150Hash": env.HIVE_FORK_TANGERINE_HASH, + "eip155Block": env.HIVE_FORK_SPURIOUS|to_int, + "eip158Block": env.HIVE_FORK_SPURIOUS|to_int, + "byzantiumBlock": env.HIVE_FORK_BYZANTIUM|to_int, + "constantinopleBlock": env.HIVE_FORK_CONSTANTINOPLE|to_int, + "petersburgBlock": env.HIVE_FORK_PETERSBURG|to_int, + "istanbulBlock": env.HIVE_FORK_ISTANBUL|to_int, + "muirGlacierBlock": env.HIVE_FORK_MUIR_GLACIER|to_int, + "berlinBlock": env.HIVE_FORK_BERLIN|to_int, + "yolov2Block": env.HIVE_FORK_BERLIN|to_int, + "yolov3Block": env.HIVE_FORK_BERLIN|to_int, + "londonBlock": env.HIVE_FORK_LONDON|to_int, + }|remove_empty +}