Skip to content

Commit

Permalink
Merge branch 'main' into better-validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Mashonskii committed Sep 11, 2024
2 parents ad34c2b + c8732c8 commit f424e1b
Show file tree
Hide file tree
Showing 18 changed files with 314 additions and 20 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
target
.bsp
.idea
docker/data
docker/logs
docker/secrets.env
35 changes: 35 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Launching the Units Network node
Units Network node consists of Waves blockchain node, Consensus Client extension, and an execution client (either [besu](https://besu.hyperledger.org) or [geth](https://geth.ethereum.org)). This directory contains sample docker compose files for running the node.

## Prerequisites
* Install [Docker Compose](https://docs.docker.com/compose/install/).
* Generate JWT secret and execution client keys by running `./gen-keys.sh`. This script requires `openssl` and `xxd`.
* Optional: get waves node [state](https://docs.waves.tech/en/waves-node/options-for-getting-actual-blockchain/state-downloading-and-applying) and place it inside the `./data/waves` directory.
* Optional: get execution client state.

## Configuring Waves Node
* Create `./secrets.env` file with the base58-encoded [seed and password](https://docs.waves.tech/en/waves-node/how-to-work-with-node-wallet):
```
WAVES_WALLET_SEED=<base58-encoded seed>
WAVES_WALLET_PASSWORD=<wallet password>
```
This wallet seed will be used for mining both waves and ethereum blocks, so make sure it's the correct one.
* Specify the proper declared addresses in the environment file (`testnet.env` for testnet, etc.). Make sure these declared addresses have distinct ports, otherwise your node will be banned from the network!

## Launching
To run besu on Linux, you need to manually create data & log directories and set appropriate permissions:
```
install -d -o 1000 -g 1000 data/besu logs/besu
```
Running, stopping and updating with besu in testnet:
```
docker compose --env-file=testnet.env up -d
docker compose --env-file=testnet.env down
docker compose --env-file=testnet.env pull
```
Running, stopping and updating with geth in testnet:
```
docker compose -f docker-compose-geth.yml --env-file=testnet.env up -d
docker compose -f docker-compose-geth.yml --env-file=testnet.env down
docker compose -f docker-compose-geth.yml --env-file=testnet.env pull
```
20 changes: 20 additions & 0 deletions docker/docker-compose-geth.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
services:
geth-init:
extends:
file: ./services/geth.yml
service: geth-init

geth:
extends:
file: ./services/geth.yml
service: geth
depends_on:
geth-init:
condition: service_completed_successfully

waves-node:
extends:
file: ./services/waves-node.yml
service: waves-node
environment:
EXECUTION_CLIENT: geth
11 changes: 11 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
besu:
extends:
file: ./services/besu.yml
service: besu
waves-node:
extends:
file: ./services/waves-node.yml
service: waves-node
environment:
EXECUTION_CLIENT: besu
4 changes: 4 additions & 0 deletions docker/gen-keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
mkdir -p data/secrets
openssl rand 32 | xxd -p -c 32 > data/secrets/p2p-key
openssl rand 32 | xxd -p -c 32 > data/secrets/jwtsecret
38 changes: 38 additions & 0 deletions docker/genesis-testnet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"alloc": {},
"baseFeePerGas": "0x3b9aca00",
"blobGasUsed": null,
"coinbase": "0x0000000000000000000000000000000000000000",
"config": {
"arrowGlacierBlock": 0,
"berlinBlock": 0,
"byzantiumBlock": 0,
"cancunTime": 0,
"chainId": 88817,
"constantinopleBlock": 0,
"daoForkBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"ethash": {},
"grayGlacierBlock": 0,
"homesteadBlock": 0,
"istanbulBlock": 0,
"londonBlock": 0,
"muirGlacierBlock": 0,
"petersburgBlock": 0,
"shanghaiTime": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true
},
"difficulty": "0x0",
"excessBlobGas": null,
"extraData": "0x",
"gasLimit": "0x1000000",
"gasUsed": "0x0",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0",
"number": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp": "0x660e5e00"
}
6 changes: 6 additions & 0 deletions docker/init-geth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
if [ ! -d /root/.ethereum/geth ] ; then
geth init /tmp/genesis.json
else
echo geth already initialized
fi
31 changes: 31 additions & 0 deletions docker/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO" monitorInterval="5">

<Properties>
<Property name="root.log.pattern">%date %-5level [%-25.25thread] %35.35c{1.} - %msg%n%throwable</Property>
</Properties>

<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout alwaysWriteExceptions="false" pattern='${root.log.pattern}'/>
</Console>
<RollingFile name="RollingFile" fileName="/opt/besu/logs/besu.log" filePattern="/opt/besu/logs/besu-%d{yyyy-MM-dd}-%i.log.gz" >
<PatternLayout alwaysWriteExceptions="false" pattern='${root.log.pattern}'/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="1000 MB" />
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</Appenders>

<Loggers>
<Logger name="oshi" level="OFF" additivity="false"/>
<Logger name="io.vertx" level="OFF" additivity="false"/>
<Root>
<AppenderRef ref="Console" level="INFO" />
<AppenderRef ref="RollingFile" level="TRACE" />
</Root>
</Loggers>

</Configuration>
3 changes: 3 additions & 0 deletions docker/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<included>

</included>
35 changes: 35 additions & 0 deletions docker/services/besu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
services:
besu:
container_name: besu
image: hyperledger/besu:latest
pull_policy: always
stop_grace_period: 5m
command:
- --logging=ALL
- --host-allowlist=*
- --rpc-http-enabled
- --rpc-http-api=ETH,NET,WEB3,TXPOOL,TRACE
- --rpc-http-cors-origins=all
- --rpc-ws-enabled
- --discovery-dns-url=enrtree://AIRIZFFZSCSIVHXTKA44WYZQJMR75FLTGWJ5TUNEW5IP7QKZDLBRK@${NETWORK}-nodes.unit0.dev
- --discovery-enabled=true
- --engine-rpc-enabled
- --engine-jwt-secret=/etc/secrets/jwtsecret
- --engine-host-allowlist=*
- --node-private-key-file=/etc/secrets/p2p-key
- --data-path=/var/lib/besu
- --genesis-file=/etc/besu/genesis.json
- --data-storage-format=BONSAI
- --network-id=${NETWORK_ID}
volumes:
- ../genesis-${NETWORK}.json:/etc/besu/genesis.json
- ../data/secrets:/etc/secrets:ro
- ../log4j2.xml:/etc/besu/log4j2.xml
- ../data/besu:/var/lib/besu
- ../logs/besu:/opt/besu/logs
ports:
- '30303:30303/tcp'
- '30303:30303/udp'
- '8545:8545'
environment:
- LOG4J_CONFIGURATION_FILE=/etc/besu/log4j2.xml
48 changes: 48 additions & 0 deletions docker/services/geth.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
services:
geth-init:
container_name: geth-init
image: ethereum/client-go:stable
entrypoint: /tmp/init-geth.sh
volumes:
- ../genesis-${NETWORK}.json:/tmp/genesis.json
- ../data/geth:/root/.ethereum
- ../init-geth.sh:/tmp/init-geth.sh
geth:
container_name: geth
image: ethereum/client-go:stable
pull_policy: always
stop_grace_period: 5m
command:
- --verbosity=4
- --http
- --http.addr=0.0.0.0
- --http.vhosts=*
- --http.api=eth,web3,txpool,net,debug,engine
- --http.corsdomain=*
- --ws
- --ws.addr=0.0.0.0
- --ws.api=eth,web3,txpool,net,debug
- --ws.rpcprefix=/
- --ws.origins=*
- --authrpc.addr=0.0.0.0
- --authrpc.vhosts=*
- --discovery.dns=enrtree://AIRIZFFZSCSIVHXTKA44WYZQJMR75FLTGWJ5TUNEW5IP7QKZDLBRK@${NETWORK}-nodes.unit0.dev
- --networkid=88817
- --authrpc.jwtsecret=/etc/secrets/jwtsecret
- --nodekey=/etc/secrets/p2p-key
logging:
driver: local
options:
max-size: 1g
max-file: 5
volumes:
- ../data/secrets:/etc/secrets:ro
- ../data/geth:/root/.ethereum
ports:
- '30303:30303/tcp'
- '30303:30303/udp'
healthcheck:
test: 'wget -qO /dev/null --header "content-type: application/json" --post-data {\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[],\"id\":1} http://127.0.0.1:8545'
interval: 5s
timeout: 1s
retries: 10
20 changes: 20 additions & 0 deletions docker/services/waves-node.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
services:
waves-node:
container_name: waves-node
image: ghcr.io/unitsnetwork/consensus-client:${WAVES_NODE_TAG:-${NETWORK}}
stop_grace_period: 5m
ports:
- "6869:6869"
- "6868:6868"
- "6865:6865"
environment:
- JAVA_OPTS=-Dwaves.config.directory=/etc/waves -Dlogback.file.level=TRACE -Dwaves.blockchain.type=$NETWORK
env_file:
- path: ../secrets.env
required: false
volumes:
- ../data/secrets:/etc/secrets:ro
- ../data/waves:/var/lib/waves/data
- ../waves-${NETWORK}.conf:/etc/waves/waves.conf:ro
- ../logback.xml:/etc/waves/logback.xml
- ../logs/waves:/var/log/waves
5 changes: 5 additions & 0 deletions docker/testnet.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
NETWORK=testnet
NETWORK_ID=88817
WAVES_NODE_TAG=L2-test
WAVES_DECLARED_ADDRESS=1.2.3.4:6868
UNITS_DECLARED_ADDRESS=1.2.3.4:6865
39 changes: 39 additions & 0 deletions docker/waves-testnet.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
waves {
extensions = [
units.ConsensusClient
]

wallet {
seed = ${WAVES_WALLET_SEED}
password = ${WAVES_WALLET_PASSWORD}
}

network {
bind-address = "0.0.0.0"
port = 6868
declared-address = ${?WAVES_DECLARED_ADDRESS}
}

rest-api {
enable = yes
bind-address = "0.0.0.0"
port = 6869
api-key-hash = ${?WAVES_API_KEY_HASH}
}

l2 {
chain-contract = 3MsqKJ6o1ABE37676cHHBxJRs6huYTt72ch
execution-client-address = "http://${EXECUTION_CLIENT}:8551"
jwt-secret-file = /etc/secrets/jwtsecret

network {
port = 6865
declared-address = ${?UNITS_DECLARED_ADDRESS}
known-peers = [
"testnet-l2-htz-hel1-2.wavesnodes.com:6865"
"testnet-htz-nbg1-1.wavesnodes.com:6865"
]
}
mining-enable = no
}
}
6 changes: 2 additions & 4 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ waves {
l2 {
chain-contract = ""

execution-client-address = "127.0.0.1"
engine-api-port = 8551
http-api-port = 8545
execution-client-address = "http://127.0.0.1:8551"
api-request-retries = 2
api-request-retry-wait-time = 2s

block-delay = 6s
block-sync-request-timeout = 2s
block-sync-request-timeout = 500ms

network = ${waves.network}
network {
Expand Down
2 changes: 0 additions & 2 deletions src/main/scala/units/ClientConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import scala.concurrent.duration.FiniteDuration
case class ClientConfig(
chainContract: String,
executionClientAddress: String,
engineApiPort: Int,
httpApiPort: Int,
apiRequestRetries: Int,
apiRequestRetryWaitTime: FiniteDuration,
blockDelay: FiniteDuration,
Expand Down
25 changes: 12 additions & 13 deletions src/main/scala/units/ConsensusClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,18 @@ class ConsensusClientDependencies(context: ExtensionContext) extends AutoCloseab
val eluScheduler: SchedulerService = Scheduler.singleThread("el-updater", reporter = { e => log.warn("Exception in ELUpdater", e) })

private val httpClientBackend = new LoggingBackend(HttpClientSyncBackend())
val engineApiClient = new HttpEngineApiClient(
config,
config.jwtSecretFile match {
case Some(secretFile) =>
val src = Source.fromFile(secretFile)
try new JwtAuthenticationBackend(src.getLines().next(), httpClientBackend)
finally src.close()
case _ =>
log.warn("JWT secret is not set")
httpClientBackend
}
)
val httpApiClient = new HttpEcApiClient(config, httpClientBackend)
private val maybeAuthenticatedBackend = config.jwtSecretFile match {
case Some(secretFile) =>
val src = Source.fromFile(secretFile)
try new JwtAuthenticationBackend(src.getLines().next(), httpClientBackend)
finally src.close()
case _ =>
log.warn("JWT secret is not set")
httpClientBackend
}

val engineApiClient = new HttpEngineApiClient(config, maybeAuthenticatedBackend)
val httpApiClient = new HttpEcApiClient(config, maybeAuthenticatedBackend)

val allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE)
val peerDatabase = new PeerDatabaseImpl(config.network)
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/units/client/engine/HttpEngineApiClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import units.eth.EthAddress
import units.{BlockHash, ClientConfig, ClientError, Job}
import play.api.libs.json.*
import sttp.client3.*
import sttp.model.Uri

import scala.concurrent.duration.{DurationInt, FiniteDuration}

class HttpEngineApiClient(val config: ClientConfig, val backend: SttpBackend[Identity, ?]) extends EngineApiClient with JsonRpcClient {

val apiUrl = uri"http://${config.executionClientAddress}:${config.engineApiPort}"
val apiUrl: Uri = Uri(config.executionClientAddress)

def forkChoiceUpdate(blockHash: BlockHash, finalizedBlockHash: BlockHash): Job[String] = {
sendEngineRequest[ForkChoiceUpdatedRequest, ForkChoiceUpdatedResponse](ForkChoiceUpdatedRequest(blockHash, finalizedBlockHash, None), BlockExecutionTimeout)
Expand Down

0 comments on commit f424e1b

Please sign in to comment.