Skip to content

Commit

Permalink
ADD: Prysm tests, fix smaller issues (#292)
Browse files Browse the repository at this point in the history
* ADD: Prysm tests, fix smaller issues

* ADD: prysm api import build path via config volume (#1)

Co-authored-by: stefa2k <[email protected]>
  • Loading branch information
NeoPlays and stefa2k authored May 19, 2022
1 parent 1b7f824 commit 75194bc
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
hosts: all
vars_files:
- ../../../../defaults/stereum_defaults.yaml

vars:
consClient: "prysm"
validator_password: "MyTestPassword"
beacon_service: 40a39644-b417-11ec-9917-3f1fbdf72a3a
validator_service: 0d4a2d58-b417-11ec-a0f3-0b91f10c3a8c
validator_keys:
- name: keystore-m_12381_3600_0_0_0-1637577658.json
Expand Down
12 changes: 11 additions & 1 deletion controls/roles/validator-import-api/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
---
- block:
- name: Looking up service configuration
slurp:
src: "/etc/stereum/services/{{ validator_service }}.yaml"
register: validator_service_config_raw
- name: Decode serivce configuration
set_fact:
validator_service_config: "{{ validator_service_config_raw.content | b64decode | from_yaml }}"
- name: Build api token path
set_fact:
auth_token_path: "{{ validator_service_config.volumes | select('search', ':/opt/app/data/wallets') | first | split(':') | first }}/auth-token"
- name: Get validator service's auth-token
slurp:
src: "/opt/app/services/{{ validator_service }}/data/wallets/auth-token"
src: "{{ auth_token_path }}"
register: auth_token
become: yes
- name: Get api-token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,6 @@ test('buildConsensusClientHttpEndpointUrl', () => {
new ServicePort('1.2.3.4', 303, 404, servicePortProtocol.udp)
]

jest.mock('./GethService')
const GethService = require('./GethService')
const mMock = jest.fn(() => { return 'http-endpoint-string' })
GethService.GethService.mockImplementation(() => {
return {
buildExecutionClientHttpEndpointUrl: mMock
}
})

const lhService = LighthouseBeaconService.buildByUserInput(networks.prater, ports, '/opt/stereum/lh', [], 16).buildConsensusClientHttpEndpointUrl()

expect(lhService).toMatch(/http:\/\/stereum-.{36}:5052/)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { LighthouseBeaconService } from './LighthouseBeaconService.js'
import { LighthouseValidatorService } from './LighthouseValidatorService.js'
import { networks } from './NodeService.js'
import { ServicePort, servicePortProtocol } from './ServicePort.js'
Expand Down
2 changes: 1 addition & 1 deletion launcher/src/backend/ethereum-services/NodeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class NodeService {

buildWorkingDir (dir) {
if(dir && dir[dir.length-1] === '/')
return dir.slice(1,-1,'') + '-' + this.id
return dir.slice(0,-1,'') + '-' + this.id
return dir + '-' + this.id
}
}
Expand Down
157 changes: 157 additions & 0 deletions launcher/src/backend/ethereum-services/PrysmBeaconService.int.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { HetznerServer } from '../HetznerServer.js'
import { NodeConnection } from '../NodeConnection.js'
import { ServicePort, servicePortProtocol } from './ServicePort.js'
import { StringUtils } from '../StringUtils.js'
import { ServiceManager } from '../ServiceManager.js'
import { PrysmBeaconService } from './PrysmBeaconService.js'
import { PrysmValidatorService } from './PrysmValidatorService.js'
const log = require('electron-log')

jest.setTimeout(1000000)

test('prysm validator import', async () => {
//create server
const testServer = new HetznerServer()
const serverSettings = {
name: 'Prysm--integration-test--ubuntu-2204',
image: 'ubuntu-22.04',
location: 'fsn1',
server_type: 'cpx21',
start_after_create: true,
}
await testServer.create(serverSettings)
log.info('server started')

const connectionParams = {
host: testServer.serverIPv4,
port: '22',
username: 'root',
password: testServer.serverRootPassword,
privatekey: undefined
}

//connect to server
const nodeConnection = new NodeConnection(connectionParams)
const serviceManager = new ServiceManager(nodeConnection)
await testServer.connect(nodeConnection)

//change password
await testServer.passwordAuthentication(testServer.serverRootPassword)

//attach to subnetwork
await testServer.attachToNetwork('eth2-prater', '10.10.0.147')
log.info('server attached to network')

//prepare node
nodeConnection.settings = { stereum: { settings: { controls_install_path: '/opt/stereum', os_user: 'stereum', updates: { in_progress: '', lane: 'stable', available: '', unattended: { check: true, install: false } } } } }
await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path);

let ports = [
new ServicePort(null, 13000, 13000, servicePortProtocol.tcp),
new ServicePort(null, 12000, 12000, servicePortProtocol.udp),
new ServicePort('127.0.0.1', 4000, 4000, servicePortProtocol.tcp)
]
let prysmBC = PrysmBeaconService.buildByUserInput('prater', ports, nodeConnection.settings.stereum.settings.controls_install_path + '/prysm', [])
//change out http address for integration test
prysmBC.command = prysmBC.command.replace('--http-web3provider=undefined','--http-web3provider=http://10.10.0.3:8545')
prysmBC.command = prysmBC.command.replace('--fallback-web3provider=undefined','--fallback-web3provider=[]')

ports = [
new ServicePort('127.0.0.1', 7500, 7500, servicePortProtocol.tcp)
]
let prysmVC = PrysmValidatorService.buildByUserInput('prater', ports, nodeConnection.settings.stereum.settings.controls_install_path + '/prysm', [prysmBC])

await Promise.all([
nodeConnection.writeServiceConfiguration(prysmBC.buildConfiguration()),
nodeConnection.writeServiceConfiguration(prysmVC.buildConfiguration())
])

await Promise.all([
serviceManager.manageServiceState(prysmBC.id, 'started'),
serviceManager.manageServiceState(prysmVC.id, 'started')
])

const wallet_path = ((prysmVC.buildConfiguration().volumes.find(volume => volume.includes('wallets'))).split(':'))[0]
log.debug(wallet_path)

const passwords_path = ((prysmVC.buildConfiguration().volumes.find(volume => volume.includes('passwords'))).split(':'))[0]
log.debug(passwords_path)


//generate wallet password
await nodeConnection.sshService.exec(`sudo echo ${StringUtils.createRandomString()} > ${passwords_path}/wallet-password`)
await nodeConnection.sshService.exec(`sudo chmod 700 ${passwords_path}/wallet-password`)
await nodeConnection.sshService.exec(`sudo chown 2000:2000 ${passwords_path}/wallet-password`)
//Prysm - Create wallet for account(s)
await nodeConnection.sshService.exec(`bash -c "docker exec stereum-${prysmVC.id} /app/cmd/validator/validator wallet create --wallet-dir=/opt/app/data/wallets --wallet-password-file=/opt/app/data/passwords/wallet-password --accept-terms-of-use --keymanager-kind=direct --prater"`)

await nodeConnection.sshService.exec(`sudo chown -R 2000:2000 ${wallet_path}`)


await Promise.all([
serviceManager.manageServiceState(prysmBC.id, 'stopped'),
serviceManager.manageServiceState(prysmVC.id, 'stopped')
])

await Promise.all([
serviceManager.manageServiceState(prysmBC.id, 'started'),
serviceManager.manageServiceState(prysmVC.id, 'started')
])
await nodeConnection.sshService.exec(`sudo chmod 600 ${wallet_path}/direct/accounts/all-accounts.keystore.json`)

await testServer.Sleep(60000)

const extraVars = {
stereum_role: 'validator-import-api', consClient: 'prysm', auth_token_path: wallet_path + '/auth-token', validator_service: prysmVC.id, validator_keys:
[{ name: 'keystore-m_12381_3600_0_0_0-1637577658.json', content: ['{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "1ccb24f0f1469ab56cc0147dae242aab59ff360177c8ec4f710966913da839b6"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "b5d944adfb65e33873c5c1b809c3c15b558821f2829cd7e9da1df65d0b78fdb6"}}, "description": "", "pubkey": "acaa51756fb445b406c9e599f3f4bec991f7799c002619566ab1fa5b70445c62f1ac6561154ca5e49d7542dbe690b96b", "path": "m/12381/3600/0/0/0", "uuid": "1ea9ed13-e3bb-4555-99d9-c5e83ab9eb67", "version": 4}'] },
{ name: 'keystore-m_12381_3600_1_0_0-1637577659.json', content: ['{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "3691a02425a4607b86292313cc72e31d4866043034ee9cff0b7cab2096105269"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "e8a184e9d70408acd33459c67632c7bb63cf9c58a175de2030f962da88a2eb4d"}}, "description": "", "pubkey": "82ed748ffbc23ee3b730577a81f4cd05fe7dba234b3de5efc31f53de67091de9631d8581d72892351dfad52b65e53fbf", "path": "m/12381/3600/1/0/0", "uuid": "f712f984-b926-4e90-a603-f3f14703bf4b", "version": 4}'] },
{ name: 'keystore-m_12381_3600_2_0_0-1637577660.json', content: ['{"crypto": {"kdf": {"function": "scrypt", "params": {"dklen": 32, "n": 262144, "r": 8, "p": 1, "salt": "de4b32f49572c01146afb11a82c326fdc03be6cf447983daf9eb7ec0f868a116"}, "message": ""}, "checksum": {"function": "sha256", "params": {}, "message": "fa52987837af01ec48e2b21f2078acef3368983943751013758052e07dae841d"}, "cipher": {"function": "aes-128-ctr", "params": {"iv": "a24857026939492f49444679544cb6bb"}, "message": "8c055c8c504cd3ad20bcb1101431b2b1a506b1a4d0efdbd294d75c39c0f2268b"}}, "description": "", "pubkey": "948f092cb5b5cae121fdc14af0e4e5a90d03ab661266b700ded1c1ca4fd6f0a76f8dac187815409197bf036675571458", "path": "m/12381/3600/2/0/0", "uuid": "c7521eed-533a-4fd1-90b7-ad1aa0f24a2d", "version": 4}'] }
]
}

await nodeConnection.runPlaybook('validator-import-api', extraVars)

//Waiting for the service to start properly
await testServer.Sleep(60000)

//get logs
const ufw = await nodeConnection.sshService.exec('ufw status')
const validatorAccounts = await nodeConnection.sshService.exec(`cat ${wallet_path}/direct/accounts/all-accounts.keystore.json`)
const auth_token = await nodeConnection.sshService.exec(`cat ${wallet_path}/auth-token`)
const BCstatus = await nodeConnection.sshService.exec(`docker logs --tail=100 stereum-${prysmBC.id}`)
const VCstatus = await nodeConnection.sshService.exec(`docker logs --tail=70 stereum-${prysmVC.id}`)
const docker = await nodeConnection.sshService.exec('docker ps')

// destroy
await nodeConnection.destroyNode()
await nodeConnection.sshService.disconnect()
await testServer.destroy()

//check ufw
expect(ufw.stdout).toMatch(/13000\/tcp/)
expect(ufw.stdout).toMatch(/12000\/udp/)
expect(ufw.stdout).toMatch(/4000\/tcp/)
expect(ufw.stdout).toMatch(/7500\/tcp/)

// Wallet & auth-token
expect(validatorAccounts.stdout).toBeTruthy()
expect(auth_token.stdout).toBeTruthy()

//check docker container
expect(docker.stdout).toMatch(/prysmaticlabs\/prysm-validator/)
expect(docker.stdout).toMatch(/prysmaticlabs\/prysm-beacon-chain/)
expect(docker.stdout).toMatch(/7500->7500/)
expect(docker.stdout).toMatch(/4000->4000/)
expect(docker.stdout).toMatch(/12000->12000/)
expect(docker.stdout).toMatch(/13000->13000/)
expect((docker.stdout.match(new RegExp('Up', 'g')) || []).length).toBe(2)

//check prysm BC logs
expect(BCstatus.stderr).toMatch(/estimated time remaining/)
//expect(BCstatus.stderr).not.toMatch(/Could not connect to execution endpoint/)

//check prysm VC logs
expect(VCstatus.stderr).toMatch(/Validating for public key/)
expect(VCstatus.stderr).toMatch(/Beacon chain started/)
//expect(VCstatus.stderr).not.toMatch(/Could not determine if beacon chain started/)
})
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class PrysmBeaconService extends NodeService {

//volumes
const volumes = [
new ServiceVolume(workingDir + '/prysm/beacon', dataDir),
new ServiceVolume(workingDir + '/beacon', dataDir),
new ServiceVolume(workingDir + '/genesis', genesisDir)
]

Expand Down
113 changes: 113 additions & 0 deletions launcher/src/backend/ethereum-services/PrysmBeaconService.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { PrysmBeaconService } from "./PrysmBeaconService";
import { networks } from './NodeService.js'
import { ServicePort, servicePortProtocol } from './ServicePort.js'
import { ServiceVolume } from './ServiceVolume.js'

test('buildConfiguration', () => {
const ports = [
new ServicePort(null, 100, 200, servicePortProtocol.tcp),
new ServicePort(null, 101, 202, servicePortProtocol.udp),
new ServicePort('1.2.3.4', 303, 404, servicePortProtocol.udp)
]

jest.mock('./GethService')
const GethService = require('./GethService')
const mMock = jest.fn(() => { return 'http-endpoint-string' })
GethService.GethService.mockImplementation(() => {
return {
buildExecutionClientHttpEndpointUrl: mMock,
buildMinimalConfiguration: jest.fn(() => {
return {
id: 'geth-id',
service: 'GethService'
}
})
}
})
const prysm = PrysmBeaconService.buildByUserInput(networks.prater, ports, '/opt/stereum/prysm/', [new GethService.GethService(),new GethService.GethService()]).buildConfiguration()

expect(prysm.command).toMatch(/--fallback-web3provider=http-endpoint-string/)
expect(prysm.command).toMatch(/--http-web3provider=http-endpoint-string/)
expect(prysm.volumes).toHaveLength(2)
expect(prysm.volumes).toContain('/opt/stereum/prysm-' + prysm.id + '/beacon:/opt/app/beacon')
expect(prysm.volumes).toContain('/opt/stereum/prysm-' + prysm.id + '/genesis:/opt/app/genesis')
expect(prysm.ports).toHaveLength(3)
expect(prysm.id).toHaveLength(36)
expect(prysm.user).toMatch(/2000/)
expect(prysm.image).toMatch(/prysmaticlabs\/prysm-beacon-chain/)
expect(prysm.configVersion).toBe(1)
})

test('buildConsensusClientHttpEndpointUrl', () => {
const ports = [
new ServicePort(null, 100, 200, servicePortProtocol.tcp),
new ServicePort(null, 101, 202, servicePortProtocol.udp),
new ServicePort('1.2.3.4', 303, 404, servicePortProtocol.udp)
]

const prysm = PrysmBeaconService.buildByUserInput(networks.prater, ports, '/opt/stereum/prysm', []).buildConsensusClientHttpEndpointUrl()

expect(prysm).toMatch(/http:\/\/stereum-.{36}:4000/)
})

test('buildConsensusClientGateway', () => {
const ports = [
new ServicePort(null, 100, 200, servicePortProtocol.tcp),
new ServicePort(null, 101, 202, servicePortProtocol.udp),
new ServicePort('1.2.3.4', 303, 404, servicePortProtocol.udp)
]

const prysm = PrysmBeaconService.buildByUserInput(networks.prater, ports, '/opt/stereum/prysm', []).buildConsensusClientGateway()

expect(prysm).toMatch(/stereum-.{36}:3500/)
})

test('buildConsensusClientEndpoint', () => {
const ports = [
new ServicePort(null, 100, 200, servicePortProtocol.tcp),
new ServicePort(null, 101, 202, servicePortProtocol.udp),
new ServicePort('1.2.3.4', 303, 404, servicePortProtocol.udp)
]

const prysm = PrysmBeaconService.buildByUserInput(networks.prater, ports, '/opt/stereum/prysm', []).buildConsensusClientEndpoint()

expect(prysm).toMatch(/stereum-.{36}:4000/)
})

test('getAvailablePorts', () => {
const prysmPorts = PrysmBeaconService.buildByUserInput(networks.prater, [], '/opt/stereum/prysm', []).getAvailablePorts()

expect(prysmPorts).toHaveLength(3)
})

test('network', () => {
const prysmNetwork = PrysmBeaconService.buildByUserInput(networks.prater, [], '/opt/stereum/prysm', []).buildConfiguration()

expect(prysmNetwork.network).toMatch(/prater/)
})

test('buildByConfiguration', () => {
const prysm = PrysmBeaconService.buildByConfiguration({
id: '321',
service: 'PrysmBeaconService',
configVersion: 216,
image: 'prysmatic:v3.2.1',
ports: ['0.0.0.0:1234:5678/tcp', '8.8.8.8:1234:5678/udp'],
volumes: ['/opt/stereum/foo:/opt/app/data']
})

expect(prysm.id).toBe('321')
expect(prysm.service).toBe('PrysmBeaconService')
expect(prysm.configVersion).toBe(216)
expect(prysm.image).toBe('prysmatic')
expect(prysm.imageVersion).toBe('v3.2.1')
expect(prysm.ports).toHaveLength(2)
expect(prysm.ports[0].destinationPort).toBe('1234')
expect(prysm.ports[1].servicePort).toBe('5678')

expect(prysm.volumes).toHaveLength(1)
expect(prysm.volumes[0]).toBeDefined()
})

// EOF

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class PrysmValidatorService extends NodeService {
1, // configVersion
image, //image
'HEAD-c8a7f6-debug', //imageVersion
'/app/cmd/validator/validator --accept-terms-of-use=true --beacon-rpc-provider="' + provider + '" --beacon-rpc-gateway-provider="' + providerGateway + '" --web=true --' + network + '=true --datadir=' + dataDir + ' --wallet-dir=' + walletDir + ' --wallet-password-file=' + passwordDir + '/wallet-password --monitoring-host=0.0.0.0 --grpc-gateway-port=7500 --grpc-gateway-host=0.0.0.0 --grpc-gateway-corsdomain="*"', //command
'/app/cmd/validator/validator --accept-terms-of-use=true --beacon-rpc-provider="' + provider + '" --beacon-rpc-gateway-provider="' + providerGateway + '" --web --' + network + '=true --datadir=' + dataDir + ' --wallet-dir=' + walletDir + ' --wallet-password-file=' + passwordDir + '/wallet-password --monitoring-host=0.0.0.0 --grpc-gateway-port=7500 --grpc-gateway-host=0.0.0.0 --grpc-gateway-corsdomain="*"', //command
null, // entrypoint
null, // env
ports, //ports
Expand Down
Loading

0 comments on commit 75194bc

Please sign in to comment.