From 4469516316d55e35c5ed43dcb883bcf34a6f337c Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 24 Dec 2020 14:25:49 -0600 Subject: [PATCH] Wyatt/update beaconchain tests (#3825) * Add lighthouse-docker command * Axios adapter, remove notImplemented check, fix query paramters * Remove notImplemented flag * Update expected responses * Remove flag from ETH2 Beacon Chain package methods schema --- CHANGELOG.md | 10 +- packages/web3-eth2-base/src/index.ts | 9 +- packages/web3-eth2-beacon/Makefile | 5 + packages/web3-eth2-beacon/src/schema.ts | 17 -- .../test/schemaMethods.test.ts | 242 ++++++++++++------ 5 files changed, 181 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f350308696..3f3c008eb6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -286,8 +286,6 @@ Released with 1.0.0-beta.37 code base. - Fix parsedUrl problem of websocket provider (#3666) - Fix return value for `clearSubscriptions` (#3689) -## [Unreleased] - ## [1.3.1] ### Added @@ -310,3 +308,11 @@ Released with 1.0.0-beta.37 code base. - Fixed decoding bytes and string parameters for logs emitted with solc 0.4.x (#3724, #3738) - Grammar changes to inputAddressFormatter error message - Fixed vulnerable dependencies + +## [Unreleased] + +## [1.3.2] + +### Changed + +- Remove `notImplemented` flag from ETH2 Beacon Chain package methods schema diff --git a/packages/web3-eth2-base/src/index.ts b/packages/web3-eth2-base/src/index.ts index 11219510c1c..800cf7a8a88 100644 --- a/packages/web3-eth2-base/src/index.ts +++ b/packages/web3-eth2-base/src/index.ts @@ -1,5 +1,7 @@ import Axios, {AxiosInstance} from 'axios' +Axios.defaults.adapter = require('axios/lib/adapters/http'); + import { ETH2BaseOpts, ETH2Function } from '../types/index' import { IBaseAPISchema } from './schema' @@ -63,17 +65,12 @@ export class ETH2Base { private buildAPIWrappersFromSchema(schema: IBaseAPISchema) { for (const method of schema.methods) { - if (method.notImplemented) { - this[method.name] = async () => { throw new Error('Method not implemented by beacon chain client') } - continue; - } - this[method.name] = async (routeParameters: any, queryParameters: any = {}): Promise => { try { if (method.inputFormatter) queryParameters = method.inputFormatter(queryParameters) const computedRoute = this.routeBuilder(method.route, routeParameters) - let {data} = await this._httpClient[method.restMethod](computedRoute, { queryParameters }) + let {data} = await this._httpClient[method.restMethod](computedRoute, { params: queryParameters }) if (data.data) data = data.data if (method.outputFormatter) data = method.outputFormatter(data) diff --git a/packages/web3-eth2-beacon/Makefile b/packages/web3-eth2-beacon/Makefile index 843c4379533..3d6b7bc8ef5 100644 --- a/packages/web3-eth2-beacon/Makefile +++ b/packages/web3-eth2-beacon/Makefile @@ -1,2 +1,7 @@ +.PHONY: lodestar-docker lighthouse-docker + lodestar-docker: docker run --network host chainsafe/lodestar beacon --testnet medalla --api.rest.enabled true + +lighthouse-docker: + docker run -p 9000:9000 -p 127.0.0.1:5052:5052 -v ${HOME}/.lighthouse:/root/.lighthouse sigp/lighthouse lighthouse --network mainnet beacon --http --http-address 0.0.0.0 diff --git a/packages/web3-eth2-beacon/src/schema.ts b/packages/web3-eth2-beacon/src/schema.ts index f74c5cf7fa0..5a21126e62a 100644 --- a/packages/web3-eth2-beacon/src/schema.ts +++ b/packages/web3-eth2-beacon/src/schema.ts @@ -14,7 +14,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get genesis block:' }, { - notImplemented: true, name: 'getHashRoot', route: 'states/${stateId}/root', restMethod: 'get', @@ -24,7 +23,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get state hash tree root:' }, { - notImplemented: true, name: 'getForkData', route: 'states/${stateId}/fork', restMethod: 'get', @@ -34,7 +32,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get fork object for state:' }, { - notImplemented: true, name: 'getFinalityCheckpoint', route: 'states/${stateId}/finality_checkpoints', restMethod: 'get', @@ -44,7 +41,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get state finality checkpoints:' }, { - notImplemented: true, name: 'getValidators', route: 'states/${stateId}/validators', restMethod: 'get', @@ -54,7 +50,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get state validators:' }, { - notImplemented: true, name: 'getValidatorById', route: 'states/${stateId}/validators/${validatorId}', restMethod: 'get', @@ -64,7 +59,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to validator from state by id:' }, { - notImplemented: true, name: 'getValidatorBalances', route: 'states/${stateId}/validator_balances', restMethod: 'get', @@ -74,7 +68,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to validator balances from state:' }, { - notImplemented: true, name: 'getEpochCommittees', route: 'states/${stateId}/committees/${epoch}', restMethod: 'get', @@ -102,7 +95,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get block header:' }, { - notImplemented: true, name: 'publishSignedBlock', route: 'blocks', restMethod: 'post', @@ -130,7 +122,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get block root:' }, { - notImplemented: true, name: 'getBlockAttestations', route: 'blocks/${blockId}/attestations', restMethod: 'get', @@ -140,7 +131,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to block attestations:' }, { - notImplemented: true, name: 'getAttestationsFromPool', route: 'pool/attestations', restMethod: 'get', @@ -150,7 +140,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to attestations from operations pool:' }, { - notImplemented: true, name: 'submitAttestation', route: 'pool/attestations', restMethod: 'post', @@ -160,7 +149,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to submit attestations to operations pool:' }, { - notImplemented: true, name: 'getAttesterSlashings', route: 'pool/attester_slashings', restMethod: 'get', @@ -170,7 +158,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get attester slashings from operations pool:' }, { - notImplemented: true, name: 'submitAttesterSlashings', route: 'pool/attester_slashings', restMethod: 'post', @@ -180,7 +167,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to submit attester slashings to operations pool:' }, { - notImplemented: true, name: 'getProposerSlashings', route: 'pool/proposer_slashings', restMethod: 'get', @@ -190,7 +176,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get proposer slashings from operations pool:' }, { - notImplemented: true, name: 'submitProposerSlashings', route: 'pool/proposer_slashings', restMethod: 'post', @@ -200,7 +185,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to submit proposer slashings to operations pool:' }, { - notImplemented: true, name: 'getSignedVoluntaryExits', route: 'pool/voluntary_exits', restMethod: 'get', @@ -210,7 +194,6 @@ export const DefaultSchema: IBaseAPISchema = { errorPrefix: 'Failed to get signed voluntary exits from operations pool' }, { - notImplemented: true, name: 'submitVoluntaryExit', route: 'pool/voluntary_exits', restMethod: 'post', diff --git a/packages/web3-eth2-beacon/test/schemaMethods.test.ts b/packages/web3-eth2-beacon/test/schemaMethods.test.ts index f8c2e11f637..9b2d9e0fc75 100644 --- a/packages/web3-eth2-beacon/test/schemaMethods.test.ts +++ b/packages/web3-eth2-beacon/test/schemaMethods.test.ts @@ -16,7 +16,8 @@ expect.extend({ let eth2BeaconChain: any // should be ETH2BeaconChain but types aren't implemented yet beforeAll(() => { - const provider = 'http://127.0.0.1:9596' // default port for Lodestar + // const provider = 'http://127.0.0.1:9596' // default port for Lodestar + const provider = 'http://127.0.0.1:5052' // default port for Lighthouse eth2BeaconChain = new ETH2Beacon(provider) }) @@ -31,66 +32,126 @@ it('getGenesis', async () => { expect(response).toMatchObject(expectedResponse) }) -it('getHashRoot - NOT IMPLEMENTED', async () => { +it('getHashRoot', async () => { const routeParameters = { stateId: 'head' } + const expectedResponse = { + root: expect.stringMatching(/0x[a-f|A-F|\d]{64}/), + } - const response = eth2BeaconChain.getHashRoot(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getHashRoot(routeParameters) + expect(response).toMatchObject(expectedResponse) }) -it('getForkData - NOT IMPLEMENTED', async () => { +it('getForkData', async () => { const routeParameters = { stateId: 'head' } + const expectedResponse = { + current_version: expect.stringMatching(/0x[a-f|A-F|\d]{8}/), + epoch: expect.stringMatching(/\d/), + previous_version: expect.stringMatching(/0x[a-f|A-F|\d]{8}/), + } - const response = eth2BeaconChain.getForkData(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getForkData(routeParameters) + expect(response).toMatchObject(expectedResponse) }) -it('getFinalityCheckpoint - NOT IMPLEMENTED', async () => { +it('getFinalityCheckpoint', async () => { const routeParameters = { stateId: 'head' } + const expectedResponse = { + current_justified: { + epoch: expect.stringMatching(/\d+/), + root: expect.stringMatching(/0x[a-f|A-F|\d]{64}/), + }, + finalized: { + epoch: expect.stringMatching(/\d+/), + root: expect.stringMatching(/0x[a-f|A-F|\d]{64}/), + }, + previous_justified: { + epoch: expect.stringMatching(/\d+/), + root: expect.stringMatching(/0x[a-f|A-F|\d]{64}/), + }, + } - const response = eth2BeaconChain.getFinalityCheckpoint(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getFinalityCheckpoint(routeParameters) + expect(response).toMatchObject(expectedResponse) }) -it('getValidators - NOT IMPLEMENTED', async () => { - const routeParameters = { stateId: 'head' } +it('getValidators', async () => { + const routeParameters = { stateId: 'genesis' } + const expectedResponse = { + balance: expect.stringMatching(/\d+/), + index: expect.stringMatching(/\d+/), + status: expect.stringMatching(/pending_initialized|pending_queued|active_ongoing|active_exiting|active_slashed|exited_unslashed|exited_slashed|withdrawal_possible|withdrawal_done|active|pending|exited|withdrawal/), + validator: { + activation_eligibility_epoch: expect.stringMatching(/\d+/), + activation_epoch: expect.stringMatching(/\d+/), + effective_balance: expect.stringMatching(/\d+/), + exit_epoch: expect.stringMatching(/\d+/), + pubkey: expect.stringMatching(/0x[a-f|A-F|\d]{96}/), + slashed: false, + withdrawable_epoch: expect.stringMatching(/\d+/), + withdrawal_credentials: expect.stringMatching(/0x[a-f|A-F|\d]{64}/), + } + } - const response = eth2BeaconChain.getValidators(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getValidators(routeParameters) + expect(response[0]).toMatchObject(expectedResponse) }) -it('getValidatorById - NOT IMPLEMENTED', async () => { +it('getValidatorById', async () => { const routeParameters = { stateId: 'head', - validatorId: '0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a' + validatorId: '0x96fb9db98b540d8500711c45fcb3608cc3fd75212457976f5b11f9f93c26701e68f846a9751e3dc2d92fa3d972a8c6b0' + } + const expectedResponse = { + balance: expect.stringMatching(/\d+/), + index: expect.stringMatching(/\d+/), + status: expect.stringMatching(/pending_initialized|pending_queued|active_ongoing|active_exiting|active_slashed|exited_unslashed|exited_slashed|withdrawal_possible|withdrawal_done|active|pending|exited|withdrawal/), + validator: { + activation_eligibility_epoch: expect.stringMatching(/\d+/), + activation_epoch: expect.stringMatching(/\d+/), + effective_balance: expect.stringMatching(/\d+/), + exit_epoch: expect.stringMatching(/\d+/), + pubkey: expect.stringMatching(/0x[a-f|A-F|\d]{96}/), + slashed: false, + withdrawable_epoch: expect.stringMatching(/\d+/), + withdrawal_credentials: expect.stringMatching(/0x[a-f|A-F|\d]{64}/), + } } - const response = eth2BeaconChain.getValidatorById(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getValidatorById(routeParameters) + expect(response).toMatchObject(expectedResponse) }) -it('getValidatorBalances - NOT IMPLEMENTED', async () => { +it('getValidatorBalances', async () => { const routeParameters = { stateId: 'head', } + const expectedResponse = { + balance: expect.stringMatching(/\d+/), + index: expect.stringMatching(/\d+/) + } - const response = eth2BeaconChain.getValidatorBalances(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getValidatorBalances(routeParameters) + expect(response[0]).toMatchObject(expectedResponse) }) -it('getEpochCommittees - NOT IMPLEMENTED', async () => { +it('getEpochCommittees', async () => { const routeParameters = { stateId: 'head', epoch: '' } - const queryParameters = { index: '1', slot: '1' } + const expectedResponse = { + index: expect.stringMatching(/\d+/), + slot: expect.stringMatching(/\d+/), + validators: expect.anything() // Only tests if not null or undefined + } - const response = eth2BeaconChain.getEpochCommittees(routeParameters, queryParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getEpochCommittees(routeParameters, queryParameters) + expect(response[0]).toMatchObject(expectedResponse) }) it('getBlockHeaders', async () => { @@ -140,9 +201,13 @@ it('getBlockHeader', async () => { expect(response).toMatchObject(expectedResponse) }) +/** + * @TODO Doesn't actually test publishing signed block, but not sure how to go about + * setting this up in a test environment to test actual publishing of blocks + */ it('publishSignedBlock', async () => { const response = eth2BeaconChain.publishSignedBlock() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + await expect(response).rejects.toThrow('Failed to publish signed block: Request failed with status code 400') }) it('getBlock', async () => { @@ -183,88 +248,111 @@ it('getBlockRoot', async () => { it('getBlockAttestations', async () => { const routeParameters = { - blockId: 'genesis', + blockId: 'head', + } + const expectedResponse = { + aggregation_bits: expect.stringMatching(/0x[a-f|A-F|\d]{2}/), + signature: expect.stringMatching(/0x[a-f|A-F|\d]{192}/), + data: { + slot: expect.stringMatching(/\d/), + index: expect.stringMatching(/\d/), + beacon_block_root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/), + source: { + epoch: expect.stringMatching(/\d/), + root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) + }, + target: { + epoch: expect.stringMatching(/\d/), + root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) + } + } } - // const expectedResponse = [ - // { - // aggregation_bits: expect.stringMatching(/0x[a-f|A-F|\d]{2}/), - // signature: expect.stringMatching(/0x[a-f|A-F|\d]{192}/), - // data: { - // slot: expect.stringMatching(/\d/), - // index: expect.stringMatching(/\d/), - // beacon_block_root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/), - // source: { - // epoch: expect.stringMatching(/\d/), - // root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) - // }, - // target: { - // epoch: expect.stringMatching(/\d/), - // root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) - // } - // } - // } - // ] - const response = eth2BeaconChain.getBlockAttestations(routeParameters) - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getBlockAttestations(routeParameters) + expect(response[0]).toMatchObject(expectedResponse) }) +/** + * @TODO queryParameters don't seem to be taken into consideration + */ it('getAttestationsFromPool', async () => { - // const expectedResponse = [ - // { - // aggregation_bits: expect.stringMatching(/0x[a-f|A-F|\d]{2}/), - // signature: expect.stringMatching(/0x[a-f|A-F|\d]{192}/), - // data: { - // slot: expect.stringMatching(/\d/), - // index: expect.stringMatching(/\d/), - // beacon_block_root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/), - // source: { - // epoch: expect.stringMatching(/\d/), - // root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) - // }, - // target: { - // epoch: expect.stringMatching(/\d/), - // root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) - // } + const queryParameters = { + slot: 1, + committee_index: 1 + } + // const expectedResponse = { + // aggregation_bits: expect.stringMatching(/0x[a-f|A-F|\d]{2}/), + // signature: expect.stringMatching(/0x[a-f|A-F|\d]{192}/), + // data: { + // slot: expect.stringMatching(/\d/), + // index: expect.stringMatching(/\d/), + // beacon_block_root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/), + // source: { + // epoch: expect.stringMatching(/\d/), + // root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) + // }, + // target: { + // epoch: expect.stringMatching(/\d/), + // root: expect.stringMatching(/0x[a-f|A-F|\d]{62}/) // } // } - // ] + // } + const expectedResponse: any[] = [] - const response = eth2BeaconChain.getAttestationsFromPool() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const response = await eth2BeaconChain.getAttestationsFromPool(null, queryParameters) + expect(response).toMatchObject(expectedResponse) }) +/** + * @TODO Doesn't actually test submitting attestation, but not sure how to go about + * setting this up in a test environment to test actual submission + */ it('submitAttestation', async () => { const response = eth2BeaconChain.submitAttestation() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + await expect(response).rejects.toThrow('Failed to submit attestations to operations pool: Request failed with status code 400') }) it('getAttesterSlashings', async () => { - const response = eth2BeaconChain.getAttesterSlashings() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const expectedResponse: any[] = [] + const response = await eth2BeaconChain.getAttesterSlashings() + expect(response).toMatchObject(expectedResponse) }) +/** + * @TODO Doesn't actually test submitting attester slashings, but not sure how to go about + * setting this up in a test environment to test actual submission + */ it('submitAttesterSlashings', async () => { const response = eth2BeaconChain.submitAttesterSlashings() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + await expect(response).rejects.toThrow('Failed to submit attester slashings to operations pool: Request failed with status code 400') }) it('getProposerSlashings', async () => { - const response = eth2BeaconChain.getProposerSlashings() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const expectedResponse: any[] = [] + const response = await eth2BeaconChain.getProposerSlashings() + expect(response).toMatchObject(expectedResponse) }) +/** + * @TODO Doesn't actually test submitting proposer slashings, but not sure how to go about + * setting this up in a test environment to test actual submission + */ it('submitProposerSlashings', async () => { const response = eth2BeaconChain.submitProposerSlashings() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + await expect(response).rejects.toThrow('Failed to submit proposer slashings to operations pool: Request failed with status code 400') }) it('getSignedVoluntaryExits', async () => { - const response = eth2BeaconChain.getSignedVoluntaryExits() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + const expectedResponse: any[] = [] + const response = await eth2BeaconChain.getSignedVoluntaryExits() + expect(response).toMatchObject(expectedResponse) }) +/** + * @TODO Doesn't actually test submitting exit, but not sure how to go about + * setting this up in a test environment to test actual submission + */ it('submitVoluntaryExit', async () => { const response = eth2BeaconChain.submitVoluntaryExit() - await expect(response).rejects.toThrow('Method not implemented by beacon chain client') + await expect(response).rejects.toThrow('Failed to submit voluntary exit to operations pool: Request failed with status code 400') })