Skip to content

Commit

Permalink
Setup docker-compose
Browse files Browse the repository at this point in the history
  • Loading branch information
masonforest committed Dec 6, 2018
1 parent 80749d5 commit 3b132b9
Show file tree
Hide file tree
Showing 29 changed files with 447 additions and 195 deletions.
9 changes: 9 additions & 0 deletions .dockerignore
@@ -1,2 +1,11 @@
deps
_build
.git/
.gitignore
config/dev*
config/test*
Dockerfile
Makefile
README*
test/
priv/static/
68 changes: 58 additions & 10 deletions Dockerfile
@@ -1,10 +1,58 @@
FROM elixir:latest
MAINTAINER Mason Fischer
RUN apt-get update
RUN apt-get install -y curl wget
RUN apt-get update
RUN apt-get install -y git build-essential libtool autoconf clang libclang-dev llvm librocksdb-dev libgmp-dev
RUN wget https://download.libsodium.org/libsodium/releases/LATEST.tar.gz && tar -xf LATEST.tar.gz && cd ./libsodium-stable && ./configure && make && make install
RUN mix local.hex --force && mix local.rebar --force
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
RUN . $HOME/.cargo/env && rustup default nightly
# Copied from https://hexdocs.pm/distillery/guides/working_with_docker.html#the-dockerfile
# Switch alpine once this issue is fixed: https://github.com/rust-lang/rustup.rs/issues/640#issuecomment-274550200
FROM elixir:1.7.4 AS builder
ARG APP_NAME=blacksmith
ARG APP_VERSION=0.1.0
ARG MIX_ENV=prod
ARG PHOENIX_SUBDIR=.
ENV APP_NAME=${APP_NAME} \
APP_VERSION=${APP_VERSION} \
MIX_ENV=${MIX_ENV}

WORKDIR /opt/app

RUN apt-get update && apt-get install -y \
autoconf \
build-essential \
curl \
git \
libgmp-dev \
libtool \
rebar &&\
mix local.rebar --force && \
mix local.hex --force

RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly
ENV PATH=/root/.cargo/bin:$PATH
COPY . .
RUN mix do deps.get, deps.compile, compile

RUN mkdir -p /opt/built
RUN ls rel/hooks
RUN mix release --verbose --env=prod
RUN cp _build/${MIX_ENV}/rel/${APP_NAME}/releases/${APP_VERSION}/${APP_NAME}.tar.gz /opt/built
RUN cd /opt/built && \
tar -xzf ${APP_NAME}.tar.gz && \
rm ${APP_NAME}.tar.gz && \
cp /opt/app/deps/libsecp256k1/priv/libsecp256k1_nif.so lib/libsecp256k1-0.1.10/priv

RUN find / -name transaction_processor
FROM debian:stretch
ARG APP_NAME

ENV REPLACE_OS_VARS=true \
APP_NAME=${APP_NAME}

WORKDIR /opt/app

COPY --from=builder /opt/built .
RUN apt-get update && apt-get install -y \
bash \
libgmp-dev \
libssl-dev \
postgresql-client \
openssl

ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
CMD trap 'exit' INT;echo $MIX_ENV; echo $WEB3_URL; /opt/app/bin/${APP_NAME} foreground
14 changes: 14 additions & 0 deletions Makefile
@@ -0,0 +1,14 @@
APP_NAME ?= `grep 'app: *:' mix.exs | sed -e 's/\[//g' -e 's/ //g' -e 's/app://' -e 's/[:,]//g'`
APP_VSN ?= `grep 'version:' mix.exs | cut -d '"' -f2`
BUILD ?= `git rev-parse --short HEAD`

build:
docker build --build-arg APP_NAME=$(APP_NAME) \
--build-arg APP_VSN=$(APP_VSN) \
-t $(APP_NAME):$(APP_VSN)-$(BUILD) \
-t $(APP_NAME):latest .

run:
docker run --env-file config/docker.env \
--expose 4045 -p 4045:4045 \
--rm -it $(APP_NAME):latest
18 changes: 4 additions & 14 deletions config/dev.exs
@@ -1,30 +1,20 @@
use Mix.Config

private_key =
<<238, 163, 60, 8, 21, 24, 67, 133, 67, 178, 163, 66, 57, 255, 25, 13, 1, 184, 12, 138, 211,
125, 187, 121, 14, 43, 17, 237, 131, 168, 205, 133>>

config :blacksmith, base_contracts_path: "./base_contracts"
config :blacksmith, port: 4047
config :blacksmith, private_key: private_key

config :blacksmith,
staking_contract_address:
"756d0ABF6235AB135126fe772CDaE195C3DECc0e" |> Base.decode16!(case: :mixed)

config :ex_wire, private_key, private_key
# private_key:
# <<18, 116, 234, 41, 220, 113, 180, 178, 230, 67, 159, 221, 16, 149, 69, 232, 193, 88, 94, 43,
# 22, 188, 212, 82, 54, 254, 32, 251, 249, 25, 167, 13>>
# config :ethereumex, :web3_url, "ws://localhost:8545/"
# config :ethereumex, :web3_url, "wss://ropsten.infura.io/ws/v3/28d900c929bf4df88e0a4adc9f790e22"
config :ethereumex, :client_type, :websocket
config :ethereumex, :web3_url, "wss://rinkeby.infura.io/ws/v3/28d900c929bf4df88e0a4adc9f790e22"
# config :ethereumex, :client_type, :http
config :blacksmith, :redis_url, "redis://127.0.0.1:6379/"

config :blacksmith, Blacksmith.Repo,
adapter: Ecto.Adapters.Postgres,
database: "test_mix",
database: "blacksmith_dev",
username: "masonf",
password: "",
hostname: "localhost"
hostname: "localhost",
log: false
12 changes: 12 additions & 0 deletions config/docker.env
@@ -0,0 +1,12 @@
MIX_ENV=PROD
APP_NAME=blacksmith
POSTGRES_HOST=postgres
POSTGRES_USER=postgres
POSTGRES_PASS=
POSTGRES_DB=blacksmith
REDIS_URL=redis://redis:6379/
PORT=4045
STAKING_CONTRACT_ADDRESS=756d0ABF6235AB135126fe772CDaE195C3DECc0e
WEB3_URL=wss://rinkeby.infura.io/ws
ETHEREUM_PRIVATE_KEY=1274EA29DC71B4B2E6439FDD109545E8C1585E2B16BCD45236FE20FBF919A70D
REPLACE_OS_VARS=true
27 changes: 9 additions & 18 deletions config/prod.exs
@@ -1,27 +1,18 @@
use Mix.Config

private_key =
<<238, 163, 60, 8, 21, 24, 67, 133, 67, 178, 163, 66, 57, 255, 25, 13, 1, 184, 12, 138, 211,
125, 187, 121, 14, 43, 17, 237, 131, 168, 205, 133>>

config :blacksmith, base_contracts_path: "./base_contracts"
config :blacksmith, port: 4047
config :blacksmith, private_key: private_key
config :blacksmith, port: String.to_integer(System.get_env("PORT") || "4045")

config :blacksmith,
staking_contract_address:
"756d0ABF6235AB135126fe772CDaE195C3DECc0e" |> Base.decode16!(case: :mixed)
(System.get_env("STAKING_CONTRACT_ADDRESS") || "") |> Base.decode16!(case: :mixed)

# config :ex_wire, private_key, private_key
# private_key:
# <<18, 116, 234, 41, 220, 113, 180, 178, 230, 67, 159, 221, 16, 149, 69, 232, 193, 88, 94, 43,
# 22, 188, 212, 82, 54, 254, 32, 251, 249, 25, 167, 13>>
config :ethereumex, :web3_url, "wss://ropsten.infura.io/ws/v3/28d900c929bf4df88e0a4adc9f790e22"
# config :ethereumex, :client_type, :websocket
config :ethereumex, :web3_url, System.get_env("WEB3_URL")
config :ethereumex, :client_type, :websocket

config :blacksmith, Blacksmith.Repo,
adapter: Ecto.Adapters.Postgres,
database: "test_mix",
username: "masonf",
password: "",
hostname: "localhost"
username: System.get_env("DATABASE_USER"),
password: System.get_env("DATABASE_PASS"),
database: System.get_env("DATABASE_NAME"),
hostname: System.get_env("DATABASE_HOST"),
pool_size: 15
5 changes: 3 additions & 2 deletions config/test.exs
Expand Up @@ -15,8 +15,9 @@ config :ex_wire,
22, 188, 212, 82, 54, 254, 32, 251, 249, 25, 167, 13>>

config :ethereumex, :web3_url, "ws://localhost:8545/"
# config :ethereumex, :web3_url, "wss://rinkeby.infura.io/ws"
# config :ethereumex, :client_type, :websocket
config :ethereumex, :web3_url, "wss://rinkeby.infura.io/ws"
config :ethereumex, :client_type, :websocket
config :blacksmith, :redis_url, "redis://127.0.0.1:6379/"
config :blacksmith, :ethereumex_auto_mine, true

config :blacksmith, Blacksmith.Repo,
Expand Down
31 changes: 31 additions & 0 deletions docker-compose.yml
@@ -0,0 +1,31 @@
version: '3.5'

services:
blacksmith:
build: .
ports:
- "4045:4045"
env_file:
- config/docker.env
depends_on:
- postgres
- redis
postgres:
image: postgres:10-alpine
# build:
# context: https://github.com/docker-library/postgres.git
# dockerfile: 11/alpine/Dockerfile
# args:
# - POSTGRES_DB=blacksmith
volumes:
- "./tmp/volumes/postgres:/var/lib/postgresql/data"
ports:
- "5432:5432"
environment:
- POSTGRES_DB=blacksmith
redis:
image: redis:5-alpine
volumes:
- "./volumes/redis:/data"
ports:
- "6379:6379"
4 changes: 2 additions & 2 deletions lib/blacksmith/application.ex
Expand Up @@ -3,8 +3,8 @@ defmodule Blacksmith.Application do
use Application

def start(_type, _args) do
:pg2.create("websocket::blocks")

# :pg2.create("websocket::blocks")
#
children = [
supervisor(Blacksmith.Repo, []),
{Redis, name: Redis},
Expand Down
7 changes: 5 additions & 2 deletions lib/crypto.ex
Expand Up @@ -7,10 +7,13 @@ defmodule Crypto do
:libsodium_crypto_sign_ed25519.keypair()
end

def hash(value) do
:crypto.hash(:sha256, value)
def hash(message) do
sha256(message)
end

def keccak256(message), do: :keccakf1600.sha3_256(message)
def sha256(message), do: :crypto.hash(:sha256, message)

def sign(message, secret_key), do: sign_ed25519(message, secret_key)

def sign_ed25519(message, secret_key) do
Expand Down
36 changes: 26 additions & 10 deletions lib/ethereum/contracts/ellipticoin_staking_contract.ex
Expand Up @@ -12,9 +12,6 @@ defmodule Ethereum.Contracts.EllipticoinStakingContract do
abi = ExW3.load_abi(abi_file_name("EllipticoinStakingContract"))
ExW3.Contract.register(__MODULE__, abi: abi)
ExW3.Contract.at(__MODULE__, bytes_to_hex(contract_address))
# IO.inspect bytes_to_hex(contract_address)
# IO.inspect ExW3.Contract.call(__MODULE__, :winner)
# IO.inspect Ethereum.Contracts.EllipticoinStakingContract.winner()
GenServer.start_link(__MODULE__, %{}, opts)
end

Expand All @@ -25,17 +22,36 @@ defmodule Ethereum.Contracts.EllipticoinStakingContract do
gas: 6_721_975
})

def submit_block(block_hash, <<r::bytes-size(32), s::bytes-size(32), recovery_id::8-integer>>, address),
do:
ExW3.Contract.send(__MODULE__, :submitBlock, [block_hash, recovery_id + 27, r, s], %{
from: address,
gas: 6_721_975
})
def submit_block(block_hash, <<r::bytes-size(32), s::bytes-size(32), recovery_id::8-integer>>) do
abi_encoded_data = ABI.encode("submitBlock(bytes32,uint8,bytes32,bytes32)", [block_hash, recovery_id + 27, r, s])
contract_address = Application.fetch_env!(:blacksmith, :staking_contract_address)
ethereum_private_key = Application.fetch_env!(:blacksmith, :ethereum_private_key)

IO.inspect recovery_id + 27, label: "v"
IO.inspect r |> Base.encode16(case: :lower), label: "r"
IO.inspect s |> Base.encode16(case: :lower), label: "s"
{:ok, transaction_count} = Ethereumex.WebSocketClient.eth_get_transaction_count(Ethereum.Helpers.bytes_to_hex(Ethereum.Helpers.my_ethereum_address()))
# IO.inspect Ethereum.Helpers.bytes_to_hex(Ethereum.Helpers.my_ethereum_address())
IO.inspect Ethereumex.WebSocketClient.eth_get_balance(Ethereum.Helpers.bytes_to_hex(Ethereum.Helpers.my_ethereum_address()))
transaction_data = %Blockchain.Transaction{
data: abi_encoded_data,
gas_price: 1000000003,
gas_limit: 4712388,
nonce: Ethereum.Helpers.hex_to_int(transaction_count),
to: contract_address,
value: 0
}
|> Blockchain.Transaction.Signature.sign_transaction(ethereum_private_key)
|> Blockchain.Transaction.serialize()
|> ExRLP.encode()
|> Base.encode16(case: :lower)

IO.inspect Ethereumex.WebSocketClient.eth_send_raw_transaction("0x" <> transaction_data)
end
def last_signature() do
{:ok, v, r, s} = ExW3.Contract.call(__MODULE__, :lastSignature)

{:ok, :binary.encode_unsigned(v) <> r <> s}
{:ok, r <> s <> :binary.encode_unsigned(v)}
end

def winner(),
Expand Down
12 changes: 8 additions & 4 deletions lib/ethereum/helpers.ex
@@ -1,4 +1,5 @@
defmodule Ethereum.Helpers do
require Integer
@address_size 20

def deploy(module_name, args \\ []) do
Expand Down Expand Up @@ -91,7 +92,7 @@ defmodule Ethereum.Helpers do

def sign(message, private_key) do
message_size = byte_size(message)
message_hash = Crypto.hash("\x19Ethereum Signed Message:\n#{message_size}" <> message)
message_hash = Crypto.keccak256("\x19Ethereum Signed Message:\n#{message_size}" <> message)
{:ok, signature, recovery_id} =
:libsecp256k1.ecdsa_sign_compact(message_hash, private_key, :default, <<>>)

Expand All @@ -105,9 +106,12 @@ defmodule Ethereum.Helpers do
:binary.part(data, length - n, n)
end

def hex_to_bytes("0x" <> hex), do: Base.decode16!(hex, case: :lower)
def hex_to_bytes("0x" <> hex), do: hex_to_bytes(hex)
def hex_to_bytes(hex) when Integer.is_odd(byte_size(hex)),
do: hex_to_bytes("0" <> hex)
def hex_to_bytes(hex), do: Base.decode16!(hex, case: :lower)
def hex_to_int(hex), do: hex_to_bytes(hex) |> :binary.decode_unsigned()
def bytes_to_hex(bytes), do: "0x" <> Base.encode16(bytes, case: :lower)
def abi_file_name(contract_name), do: Path.join(["priv", "ethereum_contracts", "#{contract_name}.abi"])
defp bin_file_name(contract_name), do: Path.join(["priv", "ethereum_contracts", "#{contract_name}.bin"])
def abi_file_name(contract_name), do: Application.app_dir(:blacksmith, ["priv", "ethereum_contracts", "#{contract_name}.abi"])
defp bin_file_name(contract_name), do: Application.app_dir(:blacksmith, ["priv", "ethereum_contracts", "#{contract_name}.bin"])
end
2 changes: 1 addition & 1 deletion lib/models/block.ex
Expand Up @@ -49,7 +49,7 @@ defmodule Models.Block do
winner: winner,
changeset_hash: changeset_hash
}

def as_cbor(block), do: Cbor.encode(as_map(block))

def forge(winner) do
Expand Down
3 changes: 2 additions & 1 deletion lib/redis.ex
Expand Up @@ -7,7 +7,8 @@ defmodule Redis do
end

def init(_args) do
{:ok, redis} = Redix.start_link()
connection_url = Application.fetch_env!(:blacksmith, :redis_url)
{:ok, redis} = Redix.start_link(connection_url)
{:ok, redis}
end

Expand Down
12 changes: 10 additions & 2 deletions lib/redis/pubsub.ex
Expand Up @@ -6,7 +6,8 @@ defmodule Redis.PubSub do
end

def init(_args) do
{:ok, pubsub} = Redix.PubSub.start_link()
connection_url = Application.fetch_env!(:blacksmith, :redis_url)
{:ok, pubsub} = Redix.PubSub.start_link(connection_url)

channels = [
:transaction_processor
Expand All @@ -33,8 +34,15 @@ defmodule Redis.PubSub do
{:noreply, state}
end

def handle_info({:redix_pubsub, _pid, _from, :subscribed, %{channel: _channel}}, state) do
{:noreply, state}

end



def handle_info(
{:redix_pubsub, _pid, :message, %{channel: channel, payload: payload}},
{:redix_pubsub, _pid, _from, :message, %{channel: channel, payload: payload}},
state = %{subscriptions: subscriptions, pubsub: _pubsub}
) do
Enum.each(subscriptions[String.to_atom(channel)], fn subscriber ->
Expand Down
9 changes: 9 additions & 0 deletions lib/release/tasks.ex
@@ -0,0 +1,9 @@
defmodule Release.Tasks do
def migrate do
{:ok, _} = Application.ensure_all_started(:blacksmith)

path = Application.app_dir(:blacksmith, ["priv", "repo", "migrations"])

Ecto.Migrator.run(Blacksmith.Repo, path, :up, all: true)
end
end

0 comments on commit 3b132b9

Please sign in to comment.