Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Stubbed] Greg/startup #71

Closed
wants to merge 10 commits into from
Closed
6 changes: 6 additions & 0 deletions beaconChain/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ethers } from "ethers";

// https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#constants
// TODO Update TBD
// TODO Explain what each constant does
Expand Down Expand Up @@ -45,3 +47,7 @@ export const MAX_CASPER_SLASHINGS = 2 ** 4; // 16
export const MAX_ATTESTATIONS = 2 ** 7; // 128
export const MAX_DEPOSITS = 2 ** 4; // 16
export const MAX_EXITS = 2 ** 4; // 16

// Smart contract addresses
export const DEPOSIT_CONTRACT_BLOCK_NUMBER = 5222222;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the use case for this?

Copy link
Member Author

@GregTheGreek GregTheGreek Dec 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually should be stubbed to "tbd". But it's the block at which the contract is deployed, so we can start looking for receipts at that block number, and then work forward.

Will add comments

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that what the ChainStart event is for? As I understand it deposits made after are still valid so I don't see the point in differentiating those made before and from those made after.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MMM good call. Pretty sure I added this earlier in the implementation

Copy link
Member Author

@GregTheGreek GregTheGreek Jan 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slight confusion, the ChainStart event is not for this. This is to reset to the block at which the contract is created at. This way we can begin looking at all deposits up to the ChainStart event.

As mentioned before, perhaps we need to re-org this a bit.

export const DEPOSIT_CONTRACT_ABI = [];
3 changes: 3 additions & 0 deletions beaconChain/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Start from './lib';

Start();
8 changes: 5 additions & 3 deletions beaconChain/interfaces/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type bytes = number;
type uint24 = number;
type uint64 = number;
type uint384 = number;
type hash32 = number;
type hash32 = string;

// Beacon chain operations

Expand Down Expand Up @@ -82,14 +82,14 @@ export interface Deposit {

export interface DepositData {
// Deposit parameters
depositParameters: DepositParameters;
depositInput: DepositInput;
// Value in Gwei
value: uint64;
// Timestamp from deposit contract
timestamp: uint64;
}

export interface DepositParameters {
export interface DepositInput {
// BLS pubkey
pubkey: uint384;
// BLS proof of possession (a BLS signature)
Expand All @@ -98,6 +98,8 @@ export interface DepositParameters {
withdrawalCredentials: hash32;
// Initial RANDAO commitment
randaoCommitment: hash32;
// Initial proof of custody commitment
pocCommitment: hash32;
}

export interface Exit {
Expand Down
12 changes: 11 additions & 1 deletion beaconChain/interfaces/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// These interfaces relate to the data structures for beacon chain state

import { AttestationData } from "./blocks";
import { AttestationData, Deposit } from "./blocks";

type bytes = number;
type uint24 = number;
Expand Down Expand Up @@ -118,3 +118,13 @@ export interface ForkData {
// Fork slot number
forkSlot: uint64;
}

// Values returned once ChainStart log is emitted
export interface ChainStart {
// Array of all deposits recorded from EthDeposit log from the eth1 contract
deposits: Deposit[];
// processedPowReceiptRoot for BeaconState
receiptRoot: hash32;
// Genesis start time
time: uint64;
}
19 changes: 19 additions & 0 deletions beaconChain/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ChainStart } from "../interfaces/state";
import { waitForChainStart } from "./powChain";

/**
* Start calls waitForChainStart, until the eth1depoist contract has executed the `ChainStart` log. Once executed, it
* will generate the initial state ("genesis block").
* @returns {Promise<void>}
* @constructor
*/
// TODO currently returns a promise due to async calls, probably a better way.
const Start = async (): Promise<void> => {
// NOTE: It is not possible to catch in this implementation, the promise only resolves.
const startConfig: ChainStart = await waitForChainStart();
// Call getInitialBeaconState() and start the beacon chain.
// const initialState = getInitialBeaconState();
// TBD...
};

export default Start;
96 changes: 96 additions & 0 deletions beaconChain/lib/powChain/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { ethers, Contract } from 'ethers';
import { EtherscanProvider } from 'ethers/providers';
import { Deposit, DepositData, DepositInput } from '../../interfaces/blocks';
import { ChainStart } from "../../interfaces/state";
import { DEPOSIT_CONTRACT_ADDRESS, DEPOSIT_CONTRACT_BLOCK_NUMBER, DEPOSIT_CONTRACT_ABI } from "../../constants/constants";

// Type stubs
type uint64 = number;
type hash32 = string;


// NOTE: This is stubbed
// TODO: We should find a way to reject the promise somehow.
// TODO: There is porbably a better way to scrape the logs.
/**
* Polls the eth1.x deposit contract for validator deposits. If the ChainStart log is emitted, return the promise with
* intial state data.
* @returns {Promise<ChainStart>}
*/
const waitForChainStart = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its plausible to test this functionality at this point, the notion of waiting for the ChainStart log isn't going to change. Please add tests if you agree.

Copy link
Member Author

@GregTheGreek GregTheGreek Dec 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know you're actually right. I'll probably have to import the vyper contract? Unless #66 gets closed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#66 has been closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some thought, you're right I can test this. The tests will only cover the actual chainstart functionality and not the deposits for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add truffle/embark? Before continuing we'll need to discuss if we want a framework for testing smart contracts or not

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about etherlime? It uses ethers.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

etherlime looks good. Still need to figure out what we want to do. Ultimately, we could do it manually.

return new Promise<ChainStart>((resolve) => {
const deposits: Deposit[] = [];

// Connect to the network
let provider = ethers.getDefaultProvider();

// Deposit Contract
let depositContract: ethers.Contract = new ethers.Contract(DEPOSIT_CONTRACT_ADDRESS, DEPOSIT_CONTRACT_ABI, provider);

// Eth1Deposit log filter
let depositTopic: string = depositContract.Eth1Deposit();
let depositFilter: ethers.EventFilter = {
address: DEPOSIT_CONTRACT_ADDRESS,
topics: [ depositTopic ]
};

// ChainStart log filter
let chainStartTopic: string = depositContract.ChainStart();
let chainStartFilter: ethers.EventFilter = {
address: DEPOSIT_CONTRACT_ADDRESS,
topics: [ chainStartTopic ]
};

// Listen for Eth1Deposit logs
provider.on(depositFilter, (previousReceiptRoot: hash32[], data: DepositData, totalDepositcount: uint64, log) => {
const newDeposit: Deposit = formatDeposit(previousReceiptRoot, data, totalDepositcount);
deposits.push(newDeposit);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the point of storing the deposits here? Should we maybe provide a function to allow their retrieval instead of discarding them in this code block?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean by discarding...
This is where classes could be very useful, and we can store to a state variable. But the objective here is we need to retrieve the deposits until chainstart emits then we take the formatted deposit[] and pass it to the next function in start to generate initial state

Copy link
Member

@ansermino ansermino Jan 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, deposits will only added until the ChainStart event resolves the promise. ie. future deposits won't be captured here. It does seem a class structure would be a way to resolve this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, that's why I created the deposits helper. Um unsure with the current spec at what point a new deposit needs to be captured. I.e what point in the state transition.

});

// Listen for ChainStart log and resolve the promise.
provider.on(chainStartFilter, (receiptRoot, time, log) => {
resolve({ deposits, receiptRoot, time });
});

// Reset filter to start when the contract was mined.
provider.resetEventsBlock(DEPOSIT_CONTRACT_BLOCK_NUMBER);
});
};

// NOTE This is stubbed.
// TODO Create custom type for param data.
// TODO Test against contract
/**
* Helper function for processing the Eth1Deposit event.
* @param {hash32[]} previousReceiptRoot
* @param data
* @param {uint64} totalDepositCount
* @returns {Deposit}
*/
const formatDeposit = (previousReceiptRoot: hash32[], data: any, totalDepositCount: uint64): Deposit => {
// Reassign values to stay consistent with camel case
const depositInput: DepositInput = {
pubkey: data.deposit_input.pubkey,
proofOfPossession: data.deposit_input.proof_of_possession,
withdrawalCredentials: data.deposit_input.withdrawal_credentials,
randaoCommitment: data.deposit_input.randao_commitment,
pocCommitment: data.deposit_input.poc_commitment
};

const depositData: DepositData = {
depositInput: depositInput,
value: data.msg_gwei_bytes8,
timestamp: data.timestamp_bytes8
};

// Formatted Deposit
return {
depositData: depositData,
merkleBranch: previousReceiptRoot,
merkleTreeIndex: totalDepositCount
};
};

export {
waitForChainStart,
};
85 changes: 83 additions & 2 deletions beaconChain/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions beaconChain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"dependencies": {
"bignumber.js": "^7.2.1",
"blakejs": "^1.1.0",
"ethers": "^4.0.20",
"ssz": "^1.5.2"
},
"bin": {
Expand Down
2 changes: 1 addition & 1 deletion beaconChain/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
Expand Down