Skip to content

Commit

Permalink
Merge branch 'unstable' into blocksv3
Browse files Browse the repository at this point in the history
  • Loading branch information
ensi321 committed Jan 12, 2024
2 parents 75b2452 + aa87c54 commit 3c20598
Show file tree
Hide file tree
Showing 16 changed files with 234 additions and 117 deletions.
15 changes: 8 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ jobs:
check-latest: true
cache: yarn

# Remove when finished debugging core dumps
- uses: './.github/actions/setup-debug-node'
# # Remove when finished debugging core dumps
# - uses: './.github/actions/setup-debug-node'

- name: Restore build cache
id: cache-primes-restore
Expand All @@ -184,13 +184,14 @@ jobs:
key: spec-test-data-${{ hashFiles('packages/validator/test/spec/params.ts') }}

- name: Unit tests
id: unit_tests
# id: unit_tests
# Rever to "yarn test:unit" when finished debugging core dumps
run: sudo sh -c "ulimit -c unlimited && /usr/bin/node-with-debug $(which yarn) test:unit"
# run: sudo sh -c "ulimit -c unlimited && /usr/bin/node-with-debug $(which yarn) test:unit"
run: yarn test:unit

# Remove when finished debugging core dumps
- uses: './.github/actions/core-dump'
if: ${{ failure() && steps.unit_tests.conclusion == 'failure' }}
# # Remove when finished debugging core dumps
# - uses: './.github/actions/core-dump'
# if: ${{ failure() && steps.unit_tests.conclusion == 'failure' }}

- name: Upload coverage data
run: yarn coverage
Expand Down
14 changes: 7 additions & 7 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ To start a new release, one of the Lodestar developers will communicate this via
- This script may alternatively be run on the checked out `HEAD`:
- `git checkout 9fceb02`
- `yarn release:create-rc 1.1.0`
- Open draft PR from `rc/v1.1.0` to `stable` with title `v1.1.0 release`.
- Open draft PR from `rc/v1.1.0` to `stable` with title `chore: v1.1.0 release`.

#### Manual steps (for example version `v1.1.0`, commit `9fceb02`):

Expand All @@ -42,7 +42,7 @@ To start a new release, one of the Lodestar developers will communicate this via
- Commit changes
- `git commit -am "v1.1.0"`
- `git push origin rc/v1.1.0`
- Open draft PR from `rc/v1.1.0` to `stable` with title `v1.1.0 release`.
- Open draft PR from `rc/v1.1.0` to `stable` with title `chore: v1.1.0 release`.

### 2. Tag release candidate

Expand Down Expand Up @@ -76,13 +76,13 @@ For example: After 3-5 days of testing, is performance equal to or better than l
- **Yes**: Continue to the next release step
- **No**: If it a small issue fixable quickly (hot-fix)?
- **Yes**: Merge fix(es) to `unstable`, push the fix(es) to `rc/v1.1.0` branch, go to step 2, incrementing the rc version
- **No**: abort the release. Close the `v1.1.0 release` PR, delete the branch, and start the whole release process over.
- **No**: abort the release. Close the `chore: v1.1.0 release` PR, delete the branch, and start the whole release process over.

### 4. Merge release candidate

- Ensure step 2 testing is successful and there is sufficient consensus to release `v1.1.0`.
- Approving the `v1.1.0 release` PR means a team member marks the release as safe, after personally reviewing and / or testing it.
- Merge `v1.1.0 release` PR to stable **with "merge commit"** strategy to preserve all history.
- Approving the `chore: v1.1.0 release` PR means a team member marks the release as safe, after personally reviewing and / or testing it.
- Merge `chore: v1.1.0 release` PR to stable **with "merge commit"** strategy to preserve all history.
- Merge stable `stable` into `unstable` **with merge commit** strategy. Due to branch protections in `unstable` must open a PR. If there are conflicts, those must be resolved manually. Gitflow may cause changes that conflict between stable and unstable, for example due to a hotfix that is backported. If that happens, disable branch protections in unstable, merge locally fixing conflicts, run lint + tests, push, and re-enable branch protections.

### 5. Tag stable release
Expand Down Expand Up @@ -130,7 +130,7 @@ A similar process for a stable release is used, with the three differences.
- Switch to the hotfix release branch and cherrypick the inclusion(s) from the `unstable` branch to the hotfix release.
- `git checkout rc/v1.1.1`
- `git cherry-pick {commit}`
- Open draft PR from `rc/v1.1.1` to `stable` with the title `v1.1.1 release`.
- Open draft PR from `rc/v1.1.1` to `stable` with the title `chore: v1.1.1 release`.

#### Manual steps (for example version `v1.1.1`, commit `8eb8dce`):

Expand All @@ -144,7 +144,7 @@ A similar process for a stable release is used, with the three differences.
- Commit changes
- `git commit -am "v1.1.1"`
- `git push origin rc/v1.1.1`
Open draft PR from `rc/v1.1.1` to `stable` with the title `v1.1.1 release`.
Open draft PR from `rc/v1.1.1` to `stable` with the title `chore: v1.1.1 release`.

### 2. Tag release candidate

Expand Down
29 changes: 25 additions & 4 deletions packages/beacon-node/src/api/impl/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import {RegenCaller} from "../../../chain/regen/index.js";
import {getValidatorStatus} from "../beacon/state/utils.js";
import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js";
import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js";
import {ChainEvent, CheckpointHex} from "../../../chain/index.js";
import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js";
import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices} from "./utils.js";

/**
Expand Down Expand Up @@ -287,7 +287,11 @@ export function getValidatorApi({
// as of now fee recipient checks can not be performed because builder does not return bid recipient
{
skipHeadChecksAndUpdate,
}: Omit<routes.validator.ExtraProduceBlockOps, "builderSelection"> & {skipHeadChecksAndUpdate?: boolean} = {}
commonBlockBody,
}: Omit<routes.validator.ExtraProduceBlockOps, "builderSelection"> & {
skipHeadChecksAndUpdate?: boolean;
commonBlockBody?: CommonBlockBody;
} = {}
): Promise<routes.validator.ProduceBlindedBlockRes> {
const version = config.getForkName(slot);
if (!isForkExecution(version)) {
Expand Down Expand Up @@ -323,6 +327,7 @@ export function getValidatorApi({
slot,
randaoReveal,
graffiti: toGraffitiBuffer(graffiti || ""),
commonBlockBody,
});

metrics?.blockProductionSuccess.inc({source});
Expand Down Expand Up @@ -352,7 +357,11 @@ export function getValidatorApi({
feeRecipient,
strictFeeRecipientCheck,
skipHeadChecksAndUpdate,
}: Omit<routes.validator.ExtraProduceBlockOps, "builderSelection"> & {skipHeadChecksAndUpdate?: boolean} = {}
commonBlockBody,
}: Omit<routes.validator.ExtraProduceBlockOps, "builderSelection"> & {
skipHeadChecksAndUpdate?: boolean;
commonBlockBody?: CommonBlockBody;
} = {}
): Promise<routes.validator.ProduceBlockOrContentsRes & {shouldOverrideBuilder?: boolean}> {
const source = ProducedBlockSource.engine;
metrics?.blockProductionRequests.inc({source});
Expand All @@ -376,6 +385,7 @@ export function getValidatorApi({
randaoReveal,
graffiti: toGraffitiBuffer(graffiti || ""),
feeRecipient,
commonBlockBody,
});
const version = config.getForkName(block.slot);
if (strictFeeRecipientCheck && feeRecipient && isForkExecution(version)) {
Expand Down Expand Up @@ -456,22 +466,32 @@ export function getValidatorApi({
chain.executionBuilder !== undefined &&
builderSelection !== routes.validator.BuilderSelection.ExecutionOnly;

logger.verbose("Assembling block with produceEngineOrBuilderBlock ", {
const loggerContext = {
fork,
builderSelection,
slot,
isBuilderEnabled,
strictFeeRecipientCheck,
// winston logger doesn't like bigint
builderBoostFactor: `${builderBoostFactor}`,
};

logger.verbose("Assembling block with produceEngineOrBuilderBlock", loggerContext);
const commonBlockBody = await chain.produceCommonBlockBody({
slot,
randaoReveal,
graffiti: toGraffitiBuffer(graffiti || ""),
});
logger.debug("Produced common block body", loggerContext);

// Start calls for building execution and builder blocks
const blindedBlockPromise = isBuilderEnabled
? // can't do fee recipient checks as builder bid doesn't return feeRecipient as of now
produceBuilderBlindedBlock(slot, randaoReveal, graffiti, {
feeRecipient,
// skip checking and recomputing head in these individual produce calls
skipHeadChecksAndUpdate: true,
commonBlockBody,
}).catch((e) => {
logger.error("produceBuilderBlindedBlock failed to produce block", {slot}, e);
return null;
Expand All @@ -494,6 +514,7 @@ export function getValidatorApi({
strictFeeRecipientCheck,
// skip checking and recomputing head in these individual produce calls
skipHeadChecksAndUpdate: true,
commonBlockBody,
}).catch((e) => {
logger.error("produceEngineFullBlockOrContents failed to produce block", {slot}, e);
return null;
Expand Down
34 changes: 28 additions & 6 deletions packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {ensureDir, writeIfNotExist} from "../util/file.js";
import {isOptimisticBlock} from "../util/forkChoice.js";
import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js";
import {ChainEventEmitter, ChainEvent} from "./emitter.js";
import {IBeaconChain, ProposerPreparationData, BlockHash, StateGetOpts} from "./interface.js";
import {IBeaconChain, ProposerPreparationData, BlockHash, StateGetOpts, CommonBlockBody} from "./interface.js";
import {IChainOptions} from "./options.js";
import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js";
import {initializeForkChoice} from "./forkChoice/index.js";
Expand Down Expand Up @@ -72,7 +72,7 @@ import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js";
import {BeaconProposerCache} from "./beaconProposerCache.js";
import {CheckpointBalancesCache} from "./balancesCache.js";
import {AssembledBlockType, BlobsResultType, BlockType} from "./produceBlock/index.js";
import {BlockAttributes, produceBlockBody} from "./produceBlock/produceBlockBody.js";
import {BlockAttributes, produceBlockBody, produceCommonBlockBody} from "./produceBlock/produceBlockBody.js";
import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js";
import {BlockInput} from "./blocks/types.js";
import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js";
Expand Down Expand Up @@ -462,14 +462,35 @@ export class BeaconChain implements IBeaconChain {
return {block: data, executionOptimistic: isOptimisticBlock(block)};
}
// If block is not found in hot db, try cold db since there could be an archive cycle happening
// TODO: Add a lock to the archiver to have determinstic behaviour on where are blocks
// TODO: Add a lock to the archiver to have deterministic behavior on where are blocks
}

const data = await this.db.blockArchive.getByRoot(fromHexString(root));
return data && {block: data, executionOptimistic: false};
}

produceBlock(blockAttributes: BlockAttributes): Promise<{
async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody> {
const {slot} = blockAttributes;
const head = this.forkChoice.getHead();
const state = await this.regen.getBlockSlotState(
head.blockRoot,
slot,
{dontTransferCache: true},
RegenCaller.produceBlock
);
const parentBlockRoot = fromHexString(head.blockRoot);

// TODO: To avoid breaking changes for metric define this attribute
const blockType = BlockType.Full;

return produceCommonBlockBody.call(this, blockType, state, {
...blockAttributes,
parentBlockRoot,
parentSlot: slot - 1,
});
}

produceBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{
block: allForks.BeaconBlock;
executionPayloadValue: Wei;
consensusBlockValue: Wei;
Expand All @@ -478,7 +499,7 @@ export class BeaconChain implements IBeaconChain {
return this.produceBlockWrapper<BlockType.Full>(BlockType.Full, blockAttributes);
}

produceBlindedBlock(blockAttributes: BlockAttributes): Promise<{
produceBlindedBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{
block: allForks.BlindedBeaconBlock;
executionPayloadValue: Wei;
consensusBlockValue: Wei;
Expand All @@ -488,7 +509,7 @@ export class BeaconChain implements IBeaconChain {

async produceBlockWrapper<T extends BlockType>(
blockType: T,
{randaoReveal, graffiti, slot, feeRecipient}: BlockAttributes
{randaoReveal, graffiti, slot, feeRecipient, commonBlockBody}: BlockAttributes & {commonBlockBody?: CommonBlockBody}
): Promise<{
block: AssembledBlockType<T>;
executionPayloadValue: Wei;
Expand Down Expand Up @@ -519,6 +540,7 @@ export class BeaconChain implements IBeaconChain {
parentBlockRoot,
proposerIndex,
proposerPubKey,
commonBlockBody,
}
);

Expand Down
24 changes: 21 additions & 3 deletions packages/beacon-node/src/chain/interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz";
import {allForks, UintNum64, Root, phase0, Slot, RootHex, Epoch, ValidatorIndex, deneb, Wei} from "@lodestar/types";
import {
allForks,
UintNum64,
Root,
phase0,
Slot,
RootHex,
Epoch,
ValidatorIndex,
deneb,
Wei,
capella,
altair,
} from "@lodestar/types";
import {
BeaconStateAllForks,
CachedBeaconStateAllForks,
Expand Down Expand Up @@ -142,13 +155,14 @@ export interface IBeaconChain {

getContents(beaconBlock: deneb.BeaconBlock): deneb.Contents;

produceBlock(blockAttributes: BlockAttributes): Promise<{
produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
produceBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{
block: allForks.BeaconBlock;
executionPayloadValue: Wei;
consensusBlockValue: Wei;
shouldOverrideBuilder?: boolean;
}>;
produceBlindedBlock(blockAttributes: BlockAttributes): Promise<{
produceBlindedBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{
block: allForks.BlindedBeaconBlock;
executionPayloadValue: Wei;
consensusBlockValue: Wei;
Expand Down Expand Up @@ -192,3 +206,7 @@ export type SSZObjectType =
| "signedAggregatedAndProof"
| "syncCommittee"
| "contributionAndProof";

export type CommonBlockBody = phase0.BeaconBlockBody &
Pick<capella.BeaconBlockBody, "blsToExecutionChanges"> &
Pick<altair.BeaconBlockBody, "syncAggregate">;
20 changes: 18 additions & 2 deletions packages/beacon-node/src/chain/opPools/opPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export class OpPool {
] {
const {config} = state;
const stateEpoch = computeEpochAtSlot(state.slot);
const stateFork = config.getForkName(state.slot);
const stateFork = config.getForkSeq(state.slot);
const toBeSlashedIndices = new Set<ValidatorIndex>();
const proposerSlashings: phase0.ProposerSlashing[] = [];

Expand Down Expand Up @@ -249,7 +249,10 @@ export class OpPool {
// Signature validation is skipped in `isValidVoluntaryExit(,,false)` since it was already validated in gossip
// However we must make sure that the signature fork is the same, or it will become invalid if included through
// a future fork.
stateFork === config.getForkName(computeStartSlotAtEpoch(voluntaryExit.message.epoch))
isVoluntaryExitSignatureIncludable(
stateFork,
config.getForkSeq(computeStartSlotAtEpoch(voluntaryExit.message.epoch))
)
) {
voluntaryExits.push(voluntaryExit);
if (voluntaryExits.length >= MAX_VOLUNTARY_EXITS) {
Expand Down Expand Up @@ -400,6 +403,19 @@ export class OpPool {
}
}

/**
* Returns true if a pre-validated signature is still valid to be included in a specific block's fork
*/
function isVoluntaryExitSignatureIncludable(stateFork: ForkSeq, voluntaryExitFork: ForkSeq): boolean {
if (stateFork >= ForkSeq.deneb) {
// Exists are perpetually valid https://eips.ethereum.org/EIPS/eip-7044
return true;
} else {
// Can only include exits from the current and previous fork
return voluntaryExitFork === stateFork || voluntaryExitFork === stateFork - 1;
}
}

function isSlashableAtEpoch(validator: phase0.Validator, epoch: Epoch): boolean {
return !validator.slashed && validator.activationEpoch <= epoch && epoch < validator.withdrawableEpoch;
}
Expand Down
Loading

0 comments on commit 3c20598

Please sign in to comment.