WIP Goerli testnet

This commit is contained in:
Yuriy Glukhov 2019-10-25 17:53:31 +03:00 committed by Zahary Karadjov
parent 43b70c0330
commit 9d3889cbab
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
12 changed files with 81 additions and 48 deletions

View File

@ -13,7 +13,7 @@ BUILD_SYSTEM_DIR := vendor/nimbus-build-system
# we don't want an error here, so we can handle things later, in the build-system-checks target
-include $(BUILD_SYSTEM_DIR)/makefiles/variables.mk
TOOLS := beacon_node bench_bls_sig_agggregation state_sim ncli_hash_tree_root ncli_pretty ncli_signing_root ncli_transition process_dashboard
TOOLS := beacon_node bench_bls_sig_agggregation state_sim ncli_hash_tree_root ncli_pretty ncli_signing_root ncli_transition process_dashboard deposit_contract
TOOLS_DIRS := beacon_chain benchmarks research ncli tests/simulation
TOOLS_CSV := $(subst $(SPACE),$(COMMA),$(TOOLS))

View File

@ -3,7 +3,7 @@ import
os, net, sequtils, tables, osproc, random, strutils, times, strformat,
# Nimble packages
stew/[objects, bitseqs],
stew/[objects, bitseqs, byteutils],
chronos, chronicles, confutils, metrics,
json_serialization/std/[options, sets], serialization/errors,
eth/trie/db, eth/trie/backends/rocksdb_backend, eth/async_utils,
@ -19,7 +19,7 @@ const
dataDirValidators = "validators"
networkMetadataFile = "network.json"
genesisFile = "genesis.json"
testnetsBaseUrl = "https://serenity-testnets.status.im"
testnetsBaseUrl = "https://raw.githubusercontent.com/status-im/nim-eth2-testnet-data/master/www"
hasPrompt = not defined(withoutPrompt)
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#interop-metrics
@ -109,27 +109,23 @@ proc saveValidatorKey(keyName, key: string, conf: BeaconNodeConf) =
writeFile(outputFile, key)
info "Imported validator key", file = outputFile
proc initGenesis(node: BeaconNode) {.async.} =
template conf: untyped = node.config
var tailState: BeaconState
if conf.depositWeb3Url.len != 0:
info "Waiting for genesis state from eth1"
tailState = await node.mainchainMonitor.getGenesis()
func stateSnapshotPath*(conf: BeaconNodeConf): string =
if conf.stateSnapshot.isSome:
conf.stateSnapshot.get.string
else:
var snapshotFile = conf.dataDir / genesisFile
conf.dataDir / genesisFile
proc getStateFromSnapshot(node: BeaconNode, state: var BeaconState): bool =
template conf: untyped = node.config
let snapshotFile = conf.stateSnapshotPath
if fileExists(snapshotFile):
template loadSnapshot(Format) =
info "Importing snapshot file", path = snapshotFile
state = loadFile(Format, snapshotFile, BeaconState)
let ext = splitFile(snapshotFile).ext
try:
if conf.stateSnapshot.isSome:
snapshotFile = conf.stateSnapshot.get.string
if not fileExists(snapshotFile):
error "Nimbus database not initialized. Please specify the initial state snapshot file."
quit 1
template loadSnapshot(Format) =
info "Importing snapshot file", path = snapshotFile
tailState = loadFile(Format, snapshotFile, BeaconState)
let ext = splitFile(snapshotFile).ext
if cmpIgnoreCase(ext, ".ssz") == 0:
loadSnapshot SSZ
elif cmpIgnoreCase(ext, ".json") == 0:
@ -137,15 +133,16 @@ proc initGenesis(node: BeaconNode) {.async.} =
else:
error "The --stateSnapshot option expects a json or a ssz file."
quit 1
except SerializationError as err:
stderr.write "Failed to import ", snapshotFile, "\n"
stderr.write err.formatMsg(snapshotFile), "\n"
quit 1
result = true
proc commitGenesisState(node: BeaconNode, tailState: BeaconState) =
info "Got genesis state", hash = hash_tree_root(tailState)
node.forkVersion = tailState.fork.current_version
try:
let tailBlock = get_initial_beacon_block(tailState)
BlockPool.preInit(node.db, tailState, tailBlock)
@ -219,9 +216,6 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
result.bootstrapNodes.add BootstrapAddr.init(string ln)
result.attachedValidators = ValidatorPool.init
if conf.depositWeb3Url.len != 0:
result.mainchainMonitor = MainchainMonitor.init(conf.depositWeb3Url, conf.depositContractAddress)
result.mainchainMonitor.start()
let trieDB = trieDB newChainDb(string conf.databaseDir)
result.db = BeaconChainDB.init(trieDB)
@ -231,8 +225,25 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
# specified on command line? potentially, this should be the other way
# around...
var eth1MonitorStartBlock: Eth2Digest
if result.db.getHeadBlock().isNone():
await result.initGenesis()
var state: BeaconState
if not result.getStateFromSnapshot(state):
if conf.depositWeb3Url.len != 0:
result.mainchainMonitor = MainchainMonitor.init(conf.depositWeb3Url, conf.depositContractAddress, eth1MonitorStartBlock)
result.mainchainMonitor.start()
else:
stderr.write "No state snapshot (or web3 URL) provided\n"
quit 1
state = await result.mainchainMonitor.getGenesis()
else:
eth1MonitorStartBlock = state.eth1Data.block_hash
result.commitGenesisState(state)
if result.mainchainMonitor.isNil and conf.depositWeb3Url.len != 0:
result.mainchainMonitor = MainchainMonitor.init(conf.depositWeb3Url, conf.depositContractAddress, eth1MonitorStartBlock)
result.mainchainMonitor.start()
result.blockPool = BlockPool.init(result.db)
result.attestationPool = AttestationPool.init(result.blockPool)
@ -1010,10 +1021,15 @@ when isMainModule:
stderr.write "Please regenerate the deposit files by running makeDeposits again\n"
quit 1
let eth1Hash = if config.depositWeb3Url.len == 0:
eth1BlockHash
else:
waitFor getLatestEth1BlockHash(config.depositWeb3Url)
var
startTime = uint64(times.toUnix(times.getTime()) + config.genesisOffset)
initialState = initialize_beacon_state_from_eth1(
eth1BlockHash, startTime, deposits, {skipValidation})
eth1Hash, startTime, deposits, {skipValidation})
# https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start#create-genesis-state
initialState.genesis_time = startTime
@ -1044,6 +1060,9 @@ when isMainModule:
totalValidators: config.totalValidators,
lastUserValidator: config.lastUserValidator)
if config.depositContractAddress.len != 0:
testnetMetadata.depositContractAddress = hexToByteArray[20](config.depositContractAddress).some
Json.saveFile(config.outputNetworkMetadata.string, testnetMetadata, pretty = true)
echo "Wrote ", config.outputNetworkMetadata.string

View File

@ -247,6 +247,7 @@ type
NetworkMetadata* = object
networkGeneration*: uint64
genesisRoot*: Option[Eth2Digest]
depositContractAddress*: Option[array[20, byte]]
bootstrapNodes*: seq[BootstrapAddr]
numShards*: uint64
slotDuration*: uint64

View File

@ -35,8 +35,10 @@ type
contract(Deposit):
proc drain()
proc getTransactionReceipt(web3: Web3, tx: TxHash): Future[ReceiptObject] {.async.} =
result = await web3.provider.eth_getTransactionReceipt(tx)
proc deployContract*(web3: Web3, code: string): Future[Address] {.async.} =
let provider = web3.provider
var code = code
if code[1] notin {'x', 'X'}:
code = "0x" & code
@ -47,7 +49,7 @@ proc deployContract*(web3: Web3, code: string): Future[Address] {.async.} =
gasPrice: 1.some)
let r = await web3.send(tr)
let receipt = await provider.eth_getTransactionReceipt(r)
let receipt = await web3.getTransactionReceipt(r)
result = receipt.contractAddress.get
proc sendEth(web3: Web3, to: string, valueEth: int): Future[TxHash] =

View File

@ -23,11 +23,12 @@ type
QueueElement = (BlockHash, DepositData)
proc init*(T: type MainchainMonitor, web3Url, depositContractAddress: string): T =
proc init*(T: type MainchainMonitor, web3Url, depositContractAddress: string, startBlock: Eth2Digest): T =
result.new()
result.web3Url = web3Url
result.depositContractAddress = Address.fromHex(depositContractAddress)
result.depositQueue = newAsyncQueue[QueueElement]()
result.eth1Block = BlockHash(startBlock.data)
contract(DepositContract):
proc deposit(pubkey: Bytes48, withdrawalCredentials: Bytes32, signature: Bytes96, deposit_data_root: FixedBytes[32])
@ -83,7 +84,7 @@ proc run(m: MainchainMonitor) {.async.} =
m.web3 = await newWeb3(m.web3Url)
let ns = m.web3.contractSender(DepositContract, m.depositContractAddress)
let s = await ns.subscribe(DepositEvent, %*{"fromBlock": "0x0"}) do(pubkey: Bytes48, withdrawalCredentials: Bytes32, amount: Bytes8, signature: Bytes96, merkleTreeIndex: Bytes8, j: JsonNode):
let s = await ns.subscribe(DepositEvent, %*{"fromBlock": m.eth1Block}) do(pubkey: Bytes48, withdrawalCredentials: Bytes32, amount: Bytes8, signature: Bytes96, merkleTreeIndex: Bytes8, j: JsonNode):
let blkHash = BlockHash.fromHex(j["blockHash"].getStr())
let amount = bytes_to_int(array[8, byte](amount))
@ -125,3 +126,9 @@ proc getPendingDeposits*(m: MainchainMonitor): seq[Deposit] =
# # rather a more readable description of the change that can be packed
# # in a SpecialRecord by the client of the API.
# discard
proc getLatestEth1BlockHash*(url: string): Future[Eth2Digest] {.async.} =
let web3 = await newWeb3(url)
let blk = await web3.provider.eth_getBlockByNumber("latest", false)
result.data = array[32, byte](blk.hash)
await web3.close()

View File

@ -13,6 +13,6 @@ mkdir -p $VALIDATORS_DIR
FIRST_IDX=$(printf '%07d' $FIRST_VALIDATOR)
LAST_IDX=$(printf '%07d' $LAST_VALIDATOR)
curl "https://serenity-testnets.status.im/${NETWORK_NAME}/v[$FIRST_IDX-$LAST_IDX].privkey" \
curl "https://raw.githubusercontent.com/status-im/nim-eth2-testnet-data/master/www/${NETWORK_NAME}/v[$FIRST_IDX-$LAST_IDX].privkey" \
-o "$VALIDATORS_DIR/v#1.privkey" -s -w '%{url_effective} > %{filename_effective}\n'

View File

@ -10,7 +10,7 @@ source "$NETWORK_NAME.env"
cd ..
if [ -f .env ]; then
# allow server overrides for ETH2_TESTNET_DATA_DIR and DATA_DIR
# allow server overrides for ETH2_TESTNET_DATA_DIR, DATA_DIR and ETH1_PRIVATE_KEY
source .env
fi
@ -41,8 +41,19 @@ ETH2_TESTNET_DATA_DIR_ABS=$(cd "$ETH2_TESTNET_DATA_DIR"; pwd)
DATA_DIR_ABS=$(mkdir -p "$DATA_DIR"; cd "$DATA_DIR"; pwd)
NETWORK_DIR_ABS="$ETH2_TESTNET_DATA_DIR_ABS/www/$NETWORK_NAME"
if [ "$WEB3_URL" != "" ]; then
WEB3_URL_ARG="--depositWeb3Url=$WEB3_URL"
fi
DOCKER_BEACON_NODE="docker run -v $NETWORK_DIR_ABS:/network_dir -v $DATA_DIR_ABS:/data_dir statusteam/nimbus_beacon_node:$NETWORK_NAME"
make deposit_contract
if [ "$ETH1_PRIVATE_KEY" != "" ]; then
DEPOSIT_CONTRACT_ADDRESS=$(./build/deposit_contract deploy $WEB3_URL_ARG --privateKey=$ETH1_PRIVATE_KEY)
DEPOSIT_CONTRACT_ADDRESS_ARG="--depositContractAddress=$DEPOSIT_CONTRACT_ADDRESS"
fi
cd docker
export GIT_REVISION=$(git rev-parse HEAD)
@ -68,6 +79,7 @@ $DOCKER_BEACON_NODE \
--outputNetworkMetadata=/network_dir/network.json \
--bootstrapAddress=$BOOTSTRAP_IP \
--bootstrapPort=$BOOTSTRAP_PORT \
$WEB3_URL_ARG $DEPOSIT_CONTRACT_ADDRESS_ARG \
--genesisOffset=60 # Delay in seconds
if [[ $PUBLISH_TESTNET_RESETS != "0" ]]; then
@ -78,14 +90,6 @@ if [[ $PUBLISH_TESTNET_RESETS != "0" ]]; then
git push
popd
echo Updating https://serenity-testnets.status.im/${NETWORK_NAME}...
ssh $BOOTSTRAP_HOST <<-SSH
cd /opt/nim-eth2-testnet-data
git reset --hard HEAD
git checkout master
git pull
SSH
echo Redistributing validator keys to server nodes...
# TODO If we try to use direct piping here, bash doesn't execute all of the commands.
# The reasons for this are unclear at the moment.

View File

@ -7,4 +7,4 @@ SECONDS_PER_SLOT=6
VALIDATOR_COUNT=1000
LAST_USER_VALIDATOR=199
BOOTSTRAP_PORT=9100
WEB3_URL=wss://goerli.infura.io/ws/v3/809a18497dd74102b5f37d25aae3c85a

2
vendor/news vendored

@ -1 +1 @@
Subproject commit 0c44ff9cd31e0f644f10d9adfbfc8e0c181ea724
Subproject commit 8ea2ee260207c57a4b495931508569e181bb7b93

2
vendor/nim-bearssl vendored

@ -1 +1 @@
Subproject commit f6133ec47de1900cc17db91fc0f929d0dcbaa63f
Subproject commit 993372dd78fa935e051e2d1f3c874d068d7171e6

2
vendor/nim-libp2p vendored

@ -1 +1 @@
Subproject commit 21af0810663901abc832ff7f29e3920a9f22392a
Subproject commit 6d8f21b611c715d19ac73901e981bf463267e797

2
vendor/nim-metrics vendored

@ -1 +1 @@
Subproject commit dc9873ebacb789c971d5496737cca0cbebcc7a9f
Subproject commit d4492f0d0ae9d2c46cc3dde2d947bc175ae420de