Skip to content
This repository was archived by the owner on Oct 6, 2025. It is now read-only.
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
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ You can find the audit report by Trail of Bits [here](https://github.com/trailof

### For Linux or MacOS users

#### File Permissions

On Unix-based systems, keystores and the `deposit_data*.json` have `440`/`-r--r-----` file permissions (user & group read only). This improves security by limiting which users and processes that have access to these files. If you are getting `permission denied` errors when handling your keystores, consider changing which user/group owns the file (with `chown`) or, if need be, change the file permissions with `chmod`.

#### Option 1. Download binary executable file

##### Step 1. Installation
Expand Down Expand Up @@ -289,10 +293,10 @@ You can also run the tool with optional arguments:
docker run -it --rm -v $(pwd)/validator_keys:/app/validator_keys ethereum/eth2.0-deposit-cli new-mnemonic --num_validators=<NUM_VALIDATORS> --mnemonic_language=english --folder=<YOUR_FOLDER_PATH>
```

Example for 1 validator on the [Medalla testnet](https://medalla.launchpad.ethereum.org/) using english:
Example for 1 validator on the [Prater testnet](https://prater.launchpad.ethereum.org/) using english:

```sh
docker run -it --rm -v $(pwd)/validator_keys:/app/validator_keys ethereum/eth2.0-deposit-cli new-mnemonic --num_validators=1 --mnemonic_language=english --chain=medalla
docker run -it --rm -v $(pwd)/validator_keys:/app/validator_keys ethereum/eth2.0-deposit-cli new-mnemonic --num_validators=1 --mnemonic_language=english --chain=prater
```

###### Arguments
Expand Down
2 changes: 2 additions & 0 deletions eth2deposit/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ def export_deposit_data_json(self, folder: str) -> str:
filefolder = os.path.join(folder, 'deposit_data-%i.json' % time.time())
with open(filefolder, 'w') as f:
json.dump(deposit_data, f, default=lambda x: x.hex())
if os.name == 'posix':
os.chmod(filefolder, int('440', 8)) # Read for owner & group
return filefolder

def verify_keystores(self, keystore_filefolders: List[str], password: str) -> bool:
Expand Down
7 changes: 5 additions & 2 deletions eth2deposit/key_handling/keystore.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
field as dataclass_field
)
import json
import os
from py_ecc.bls import G2ProofOfPossession as bls
from secrets import randbits
from typing import Any, Dict, Union
Expand Down Expand Up @@ -90,12 +91,14 @@ class Keystore(BytesDataclass):
def kdf(self, **kwargs: Any) -> bytes:
return scrypt(**kwargs) if 'scrypt' in self.crypto.kdf.function else PBKDF2(**kwargs)

def save(self, file: str) -> None:
def save(self, filefolder: str) -> None:
"""
Save self as a JSON keystore.
"""
with open(file, 'w') as f:
with open(filefolder, 'w') as f:
f.write(self.as_json())
if os.name == 'posix':
os.chmod(filefolder, int('440', 8)) # Read for owner & group

@classmethod
def from_json(cls, json_dict: Dict[Any, Any]) -> 'Keystore':
Expand Down
26 changes: 5 additions & 21 deletions eth2deposit/settings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Dict, NamedTuple


DEPOSIT_CLI_VERSION = '1.1.0'
DEPOSIT_CLI_VERSION = '1.1.1'


class BaseChainSetting(NamedTuple):
Expand All @@ -10,38 +10,22 @@ class BaseChainSetting(NamedTuple):


MAINNET = 'mainnet'
WITTI = 'witti'
ALTONA = 'altona'
MEDALLA = 'medalla'
SPADINA = 'spadina'
ZINKEN = 'zinken'
PYRMONT = 'pyrmont'
PRATER = 'prater'


# Eth2 Mainnet setting
MainnetSetting = BaseChainSetting(ETH2_NETWORK_NAME=MAINNET, GENESIS_FORK_VERSION=bytes.fromhex('00000000'))
# Eth2 spec v0.11.3 testnet
WittiSetting = BaseChainSetting(ETH2_NETWORK_NAME=WITTI, GENESIS_FORK_VERSION=bytes.fromhex('00000113'))
# Eth2 spec v0.12.1 testnet
AltonaSetting = BaseChainSetting(ETH2_NETWORK_NAME=ALTONA, GENESIS_FORK_VERSION=bytes.fromhex('00000121'))
# Eth2 "official" public testnet (spec v0.12.2)
MedallaSetting = BaseChainSetting(ETH2_NETWORK_NAME=MEDALLA, GENESIS_FORK_VERSION=bytes.fromhex('00000001'))
# Eth2 "dress rehearsal" testnet (spec v0.12.3)
SpadinaSetting = BaseChainSetting(ETH2_NETWORK_NAME=SPADINA, GENESIS_FORK_VERSION=bytes.fromhex('00000002'))
# Eth2 "dress rehearsal" testnet (spec v0.12.3)
ZinkenSetting = BaseChainSetting(ETH2_NETWORK_NAME=ZINKEN, GENESIS_FORK_VERSION=bytes.fromhex('00000003'))
# Eth2 pre-launch testnet (spec v1.0.0)
PyrmontSetting = BaseChainSetting(ETH2_NETWORK_NAME=PYRMONT, GENESIS_FORK_VERSION=bytes.fromhex('00002009'))
# Eth2 testnet (spec v1.0.1)
PraterSetting = BaseChainSetting(ETH2_NETWORK_NAME=PRATER, GENESIS_FORK_VERSION=bytes.fromhex('00001020'))


ALL_CHAINS: Dict[str, BaseChainSetting] = {
MAINNET: MainnetSetting,
WITTI: WittiSetting,
ALTONA: AltonaSetting,
MEDALLA: MedallaSetting,
SPADINA: SpadinaSetting,
ZINKEN: ZinkenSetting,
PYRMONT: PyrmontSetting,
PRATER: PraterSetting,
}


Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name="eth2deposit",
version='1.1.0',
version='1.1.1',
py_modules=["eth2deposit"],
packages=find_packages(exclude=('tests', 'docs')),
python_requires=">=3.7,<4",
Expand Down
4 changes: 4 additions & 0 deletions tests/test_cli/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ def clean_key_folder(my_folder_path: str) -> None:
def get_uuid(key_file: str) -> str:
keystore = Keystore.from_file(key_file)
return keystore.uuid


def get_permissions(path: str, file_name: str) -> str:
return oct(os.stat(os.path.join(path, file_name)).st_mode & 0o777)
11 changes: 10 additions & 1 deletion tests/test_cli/test_existing_menmonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from eth2deposit.deposit import cli
from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME
from.helpers import clean_key_folder, get_uuid
from.helpers import clean_key_folder, get_permissions, get_uuid


def test_existing_mnemonic() -> None:
Expand Down Expand Up @@ -38,6 +38,10 @@ def test_existing_mnemonic() -> None:
]
assert len(set(all_uuid)) == 5

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'
# Clean up
clean_key_folder(my_folder_path)

Expand Down Expand Up @@ -85,5 +89,10 @@ async def test_script() -> None:
validator_keys_folder_path = os.path.join(my_folder_path, DEFAULT_VALIDATOR_KEYS_FOLDER_NAME)
_, _, key_files = next(os.walk(validator_keys_folder_path))

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'

# Clean up
clean_key_folder(my_folder_path)
12 changes: 11 additions & 1 deletion tests/test_cli/test_new_mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from eth2deposit.cli import new_mnemonic
from eth2deposit.deposit import cli
from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME
from .helpers import clean_key_folder, get_uuid
from .helpers import clean_key_folder, get_permissions, get_uuid


def test_new_mnemonic(monkeypatch) -> None:
Expand Down Expand Up @@ -40,6 +40,11 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
]
assert len(set(all_uuid)) == 1

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'

# Clean up
clean_key_folder(my_folder_path)

Expand Down Expand Up @@ -103,5 +108,10 @@ async def test_script() -> None:
]
assert len(set(all_uuid)) == 5

# Verify file permissions
if os.name == 'posix':
for file_name in key_files:
assert get_permissions(validator_keys_folder_path, file_name) == '0o440'

# Clean up
clean_key_folder(my_folder_path)
12 changes: 11 additions & 1 deletion tests/test_cli/test_regeneration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from eth2deposit.cli import new_mnemonic
from eth2deposit.deposit import cli
from eth2deposit.utils.constants import DEFAULT_VALIDATOR_KEYS_FOLDER_NAME
from .helpers import clean_key_folder, get_uuid
from .helpers import clean_key_folder, get_permissions, get_uuid


def test_regeneration(monkeypatch) -> None:
Expand Down Expand Up @@ -47,6 +47,11 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
for key_file in part_1_key_files]
assert len(set(all_uuid)) == 2

# Verify file permissions
if os.name == 'posix':
for file_name in part_1_key_files:
assert get_permissions(validator_keys_folder_path_1, file_name) == '0o440'

# Part 2: existing-mnemonic
runner = CliRunner()
# Create index 1 and 2
Expand Down Expand Up @@ -78,6 +83,11 @@ def mock_get_mnemonic(language, words_path, entropy=None) -> str:
assert keystore_1_1['pubkey'] == keystore_2_0['pubkey']
assert keystore_1_1['path'] == keystore_2_0['path']

# Verify file permissions
if os.name == 'posix':
for file_name in part_2_key_files:
assert get_permissions(validator_keys_folder_path_2, file_name) == '0o440'

# Clean up
clean_key_folder(folder_path_1)
clean_key_folder(folder_path_2)
4 changes: 2 additions & 2 deletions tests/test_credentials.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

from eth2deposit.credentials import CredentialList
from eth2deposit.settings import MedallaSetting
from eth2deposit.settings import MainnetSetting


def test_from_mnemonic() -> None:
Expand All @@ -11,6 +11,6 @@ def test_from_mnemonic() -> None:
mnemonic_password="",
num_keys=1,
amounts=[32, 32],
chain_setting=MedallaSetting,
chain_setting=MainnetSetting,
start_index=1,
)