Skip to content

Commit

Permalink
fix: calculate and verify genesis block state hash (#872)
Browse files Browse the repository at this point in the history
* calculate and verify genesis block state hash

* include genesis info in state hash calculation

* calculate and verify logsBloom for genesis block

* regenerate configs

* style: resolve style guide violations

* check options.distribute

* improve state hash check

* style: resolve style guide violations
  • Loading branch information
oXtxNt9U authored Feb 27, 2025
1 parent 76c7504 commit 303f3d9
Show file tree
Hide file tree
Showing 26 changed files with 2,959 additions and 2,900 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ describe<{
distribute: true,
epoch: new Date(),
premine: "2000000000",
}),
validators: 53,
} as Contracts.NetworkGenerator.InternalOptions),
);
});
});
73 changes: 49 additions & 24 deletions packages/configuration-generator/source/generators/genesis-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,12 @@ export class GenesisBlockGenerator extends Generator {
@tagged("instance", "evm")
private readonly evm!: Contracts.Evm.Instance;

@inject(EvmConsensusIdentifiers.Internal.Addresses.Deployer)
private readonly deployerAddress!: string;

#consensusProxyContractAddress!: string;

async generate(
genesisMnemonic: string,
validatorsMnemonics: string[],
options: Contracts.NetworkGenerator.GenesisBlockOptions,
options: Contracts.NetworkGenerator.InternalOptions,
): Promise<Contracts.Crypto.CommitData> {
const genesisWallet = await this.createWallet(genesisMnemonic);

Expand Down Expand Up @@ -96,13 +93,17 @@ export class GenesisBlockGenerator extends Generator {

async #prepareEvm(
genesisWalletAddress: string,
_validatorsCount: number,
options: Contracts.NetworkGenerator.GenesisBlockOptions,
validatorsCount: number,
options: Contracts.NetworkGenerator.InternalOptions,
) {
await this.app.resolve(Deployer).deploy({
generatorAddress: genesisWalletAddress,
timestamp: dayjs(options.epoch).valueOf(),
totalAmount: options.premine,
totalAmount: (options.distribute
? // Ensure no left over remains when distributing funds from the genesis address (see `#createTransferTransactions`)
BigNumber.make(options.premine).dividedBy(validatorsCount).times(validatorsCount)
: BigNumber.make(options.premine)
).toString(),
});

this.#consensusProxyContractAddress = this.app.get<string>(
Expand Down Expand Up @@ -201,7 +202,7 @@ export class GenesisBlockGenerator extends Generator {
async #createGenesisCommit(
premineKeys: Contracts.Crypto.KeyPair,
transactions: Contracts.Crypto.Transaction[],
options: Contracts.NetworkGenerator.GenesisBlockOptions,
options: Contracts.NetworkGenerator.InternalOptions,
): Promise<Contracts.Crypto.Commit> {
const genesisBlock = await this.#createGenesisBlock(premineKeys, transactions, options);

Expand All @@ -225,7 +226,7 @@ export class GenesisBlockGenerator extends Generator {
async #createGenesisBlock(
keys: Contracts.Crypto.KeyPair,
transactions: Contracts.Crypto.Transaction[],
options: Contracts.NetworkGenerator.GenesisBlockOptions,
options: Contracts.NetworkGenerator.InternalOptions,
): Promise<{ block: Contracts.Crypto.Block; transactions: Contracts.Crypto.TransactionData[] }> {
const totals: { amount: BigNumber; fee: BigNumber; gasUsed: number } = {
amount: BigNumber.ZERO,
Expand All @@ -234,11 +235,25 @@ export class GenesisBlockGenerator extends Generator {
};

const payloadBuffers: Buffer[] = [];
const commitKey = {
height: BigInt(0),
round: BigInt(0),
};
const timestamp = BigInt(dayjs(options.epoch).valueOf());
const generatorAddress = await this.app
.getTagged<Contracts.Crypto.AddressFactory>(
Identifiers.Cryptography.Identity.Address.Factory,
"type",
"wallet",
)
.fromPublicKey(keys.publicKey);

// The initial payload length takes the overhead for each serialized transaction into account
// which is a uint32 per transaction to store the individual length.
let payloadLength = transactions.length * 4;

await this.evm.prepareNextCommit({ commitKey });

const transactionData: Contracts.Crypto.TransactionData[] = [];
for (const transaction of transactions) {
const { serialized, data } = transaction;
Expand All @@ -247,13 +262,10 @@ export class GenesisBlockGenerator extends Generator {

const { receipt } = await this.evm.process({
blockContext: {
commitKey: {
height: BigInt(0),
round: BigInt(0),
},
commitKey,
gasLimit: BigInt(30_000_000),
timestamp: BigInt(dayjs(options.epoch).valueOf()),
validatorAddress: this.deployerAddress,
timestamp,
validatorAddress: generatorAddress,
},
caller: transaction.data.senderAddress,
data: Buffer.from(transaction.data.data, "hex"),
Expand All @@ -276,18 +288,28 @@ export class GenesisBlockGenerator extends Generator {
payloadLength += serialized.length;
}

await this.evm.updateRewardsAndVotes({
blockReward: 0n,
commitKey,
specId: Contracts.Evm.SpecId.SHANGHAI,
timestamp,
validatorAddress: generatorAddress,
});

await this.evm.calculateActiveValidators({
activeValidators: Utils.BigNumber.make(options.validators).toBigInt(),
commitKey,
specId: Contracts.Evm.SpecId.SHANGHAI,
timestamp,
validatorAddress: generatorAddress,
});

return {
block: await this.app.get<Contracts.Crypto.BlockFactory>(Identifiers.Cryptography.Block.Factory).make(
{
generatorAddress: await this.app
.getTagged<Contracts.Crypto.AddressFactory>(
Identifiers.Cryptography.Identity.Address.Factory,
"type",
"wallet",
)
.fromPublicKey(keys.publicKey),
generatorAddress,
height: 0,
logsBloom: "0".repeat(512),
logsBloom: await this.evm.logsBloom(commitKey),
numberOfTransactions: transactions.length,
payloadHash: (
await this.app
Expand All @@ -302,7 +324,10 @@ export class GenesisBlockGenerator extends Generator {
round: 0,
stateHash:
options.snapshot?.stateHash ??
"0000000000000000000000000000000000000000000000000000000000000000",
(await this.evm.stateHash(
commitKey,
"0000000000000000000000000000000000000000000000000000000000000000",
)),
timestamp: dayjs(options.epoch).valueOf(),
totalAmount: options.snapshot ? Utils.BigNumber.make(options.premine) : totals.amount,
totalFee: totals.fee,
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/source/contracts/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface LegacyImporter {
validators: ImportedLegacyValidator[];
voters: ImportedLegacyVoter[];
snapshotHash: string;
result: LegacyImportResult | undefined;
}

export interface LegacyImportOptions {
Expand Down
Loading

0 comments on commit 303f3d9

Please sign in to comment.